@streamfox/create-streamfox-plugin 0.3.0 → 0.3.2
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 +5 -7
- package/dist/cli.cjs +32 -54
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +32 -54
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +16 -34
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +16 -34
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli.ts","../package.json","../src/scaffold.ts"],"sourcesContent":["import path from \"node:path\";\nimport { Command, InvalidArgumentError } from \"commander\";\nimport prompts from \"prompts\";\nimport packageJSON from \"../package.json\";\nimport {\n CAPABILITIES,\n DEFAULT_PRESET,\n DEFAULT_SDK_VERSION,\n scaffoldProject,\n type Capability,\n type Language,\n type Preset,\n} from \"./scaffold\";\n\nfunction capabilitiesLabel(): string {\n return CAPABILITIES.join(\", \");\n}\n\nfunction parsePreset(input: string): Preset {\n if (CAPABILITIES.includes(input as Capability)) {\n return input as Preset;\n }\n throw new InvalidArgumentError(\n `Invalid preset '${input}'. Use one of: ${capabilitiesLabel()}`,\n );\n}\n\nfunction parseCapabilitiesList(input: string): Capability[] {\n const parsed = input\n .split(\",\")\n .map((value) => value.trim())\n .filter((value) => value.length > 0) as Capability[];\n\n for (const capability of parsed) {\n if (!CAPABILITIES.includes(capability)) {\n throw new InvalidArgumentError(\n `Invalid capability '${capability}'. Use one of: ${capabilitiesLabel()}`,\n );\n }\n }\n\n return Array.from(new Set(parsed));\n}\n\nconst program = new Command();\n\nprogram\n .name(\"create-streamfox-plugin\")\n .version(packageJSON.version, \"-v, --version\", \"display the current CLI version\")\n .description(\"Scaffold StreamFox plugin projects with modern JS/TS presets\")\n .showHelpAfterError()\n .argument(\"[directory]\", \"output directory\")\n .option(\"--ts\", \"use TypeScript template\")\n .option(\"--js\", \"use JavaScript template\")\n .option(\n \"--preset <preset>\",\n `plugin preset: ${capabilitiesLabel()}`,\n parsePreset,\n )\n .option(\n \"--capabilities <capabilities>\",\n \"extra capabilities as comma-separated list\",\n parseCapabilitiesList,\n )\n .option(\"--advanced\", \"generate advanced capability examples\")\n .option(\n \"--sdk-version <range>\",\n \"@streamfox/plugin-sdk version/range\",\n DEFAULT_SDK_VERSION,\n )\n .option(\"--yes\", \"skip prompts and use defaults\")\n .action(\n async (\n directoryArg: string | undefined,\n options: {\n ts?: boolean;\n js?: boolean;\n yes?: boolean;\n preset?: Preset;\n capabilities?: Capability[];\n advanced?: boolean;\n sdkVersion?: string;\n },\n ) => {\n if (options.ts && options.js) {\n throw new InvalidArgumentError(\"Choose either --ts or --js, not both.\");\n }\n\n const promptDefaults = {\n directory: directoryArg ?? \"my-media-plugin\",\n language: options.ts ? \"ts\" : options.js ? \"js\" : \"ts\",\n preset: options.preset ?? DEFAULT_PRESET,\n extraCapabilities: options.capabilities ?? [],\n advanced: options.advanced ?? false,\n sdkVersion: options.sdkVersion ?? DEFAULT_SDK_VERSION,\n };\n\n const shouldPrompt = !options.yes;\n\n let directory = promptDefaults.directory;\n let language = promptDefaults.language as Language;\n let preset = promptDefaults.preset;\n let extraCapabilities = promptDefaults.extraCapabilities;\n let advanced = promptDefaults.advanced;\n let sdkVersion = promptDefaults.sdkVersion;\n\n if (shouldPrompt) {\n const answers = await prompts(\n [\n {\n type: \"text\",\n name: \"directory\",\n message: \"Project directory\",\n initial: directory,\n },\n {\n type: \"select\",\n name: \"language\",\n message: \"Template language\",\n choices: [\n { title: \"TypeScript\", value: \"ts\" },\n { title: \"JavaScript\", value: \"js\" },\n ],\n initial: language === \"ts\" ? 0 : 1,\n },\n {\n type: \"select\",\n name: \"preset\",\n message: \"Plugin preset\",\n choices: CAPABILITIES.map((capability) => ({\n title: capability,\n value: capability,\n })),\n initial: CAPABILITIES.indexOf(preset),\n },\n {\n type: \"multiselect\",\n name: \"extraCapabilities\",\n message: \"Extra capabilities (optional)\",\n choices: CAPABILITIES.map((capability) => ({\n title: capability,\n value: capability,\n })),\n instructions: false,\n min: 0,\n hint: \"Space to select\",\n },\n {\n type: \"confirm\",\n name: \"advanced\",\n message: \"Generate advanced capability examples?\",\n initial: advanced,\n },\n {\n type: \"text\",\n name: \"sdkVersion\",\n message: \"SDK dependency version/range\",\n initial: sdkVersion,\n },\n ],\n {\n onCancel: () => {\n process.exit(1);\n },\n },\n );\n\n directory = answers.directory;\n language = answers.language;\n preset = (answers.preset ?? promptDefaults.preset) as Preset;\n extraCapabilities = (answers.extraCapabilities ?? []) as Capability[];\n advanced = Boolean(answers.advanced ?? promptDefaults.advanced);\n sdkVersion = answers.sdkVersion ?? promptDefaults.sdkVersion;\n }\n\n const targetDir = path.resolve(process.cwd(), directory);\n const projectName = path.basename(targetDir);\n\n await scaffoldProject({\n targetDir,\n projectName,\n language,\n preset,\n extraCapabilities,\n advanced,\n sdkVersion,\n });\n\n console.log(`Created ${projectName} at ${targetDir}`);\n console.log(\"Next steps:\");\n console.log(` cd ${directory}`);\n console.log(\" npm install\");\n console.log(\" npm run dev\");\n },\n );\n\nvoid program.parseAsync(process.argv).catch((error: unknown) => {\n const message = error instanceof Error ? error.message : String(error);\n console.error(`Error: ${message}`);\n process.exit(1);\n});\n","{\n \"name\": \"@streamfox/create-streamfox-plugin\",\n \"version\": \"0.3.0\",\n \"description\": \"Standalone CLI to scaffold StreamFox plugin projects\",\n \"type\": \"module\",\n \"bin\": {\n \"create-streamfox-plugin\": \"dist/cli.cjs\"\n },\n \"main\": \"./dist/index.cjs\",\n \"module\": \"./dist/index.js\",\n \"types\": \"./dist/index.d.ts\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.js\",\n \"require\": \"./dist/index.cjs\"\n }\n },\n \"files\": [\n \"dist\",\n \"README.md\"\n ],\n \"scripts\": {\n \"build\": \"tsup\",\n \"format\": \"prettier --write .\",\n \"format:check\": \"prettier --check .\",\n \"test\": \"vitest run\",\n \"typecheck\": \"tsc --noEmit\",\n \"check\": \"npm run format:check && npm run typecheck && npm test && npm run build\"\n },\n \"dependencies\": {\n \"commander\": \"^12.1.0\",\n \"prompts\": \"^2.4.2\"\n },\n \"devDependencies\": {\n \"@types/node\": \"^24.6.0\",\n \"@types/prompts\": \"^2.4.9\",\n \"prettier\": \"^3.6.2\",\n \"tsup\": \"^8.5.0\",\n \"typescript\": \"^5.9.2\",\n \"vitest\": \"^2.1.9\"\n },\n \"engines\": {\n \"node\": \">=20\"\n }\n}\n","import { access, mkdir, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\n\nexport const CAPABILITIES = [\n \"catalog\",\n \"meta\",\n \"stream\",\n \"subtitles\",\n \"plugin_catalog\",\n] as const;\nexport type Capability = (typeof CAPABILITIES)[number];\nexport type Preset = Capability;\nexport type Language = \"ts\" | \"js\";\nexport const DEFAULT_PRESET: Preset = \"meta\";\nexport const DEFAULT_SDK_VERSION = \"^0.2.0\";\n\nexport interface ScaffoldOptions {\n targetDir: string;\n projectName: string;\n language: Language;\n preset: Preset;\n advanced?: boolean;\n extraCapabilities?: Capability[];\n sdkVersion?: string;\n}\n\nfunction sortedCapabilities(values: Capability[]): Capability[] {\n const unique = Array.from(new Set(values));\n return CAPABILITIES.filter((capability) => unique.includes(capability));\n}\n\nasync function ensureTargetDoesNotExist(targetDir: string): Promise<void> {\n try {\n await access(targetDir);\n throw new Error(`Target directory already exists: ${targetDir}`);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n return;\n }\n throw error;\n }\n}\n\nfunction makePackageJson(\n name: string,\n language: Language,\n sdkVersion: string,\n): string {\n const scripts =\n language === \"ts\"\n ? {\n dev: \"tsx watch src/server.ts\",\n build: \"tsc -p tsconfig.json\",\n format: \"prettier --write .\",\n \"format:check\": \"prettier --check .\",\n start: \"node dist/server.js\",\n test: \"vitest run\",\n typecheck: \"tsc --noEmit\",\n }\n : {\n dev: \"node --watch src/server.js\",\n build: 'echo \"No build step for JavaScript template\"',\n format: \"prettier --write .\",\n \"format:check\": \"prettier --check .\",\n start: \"node src/server.js\",\n test: \"vitest run\",\n };\n\n const normalizedScripts = {\n ...scripts,\n check:\n language === \"ts\"\n ? \"npm run format:check && npm run typecheck && npm test && npm run build\"\n : \"npm run format:check && npm test && npm run build\",\n };\n\n const packageJson = {\n name,\n version: \"0.1.0\",\n private: true,\n type: \"module\",\n scripts: normalizedScripts,\n dependencies: {\n \"@streamfox/plugin-sdk\": sdkVersion,\n },\n devDependencies:\n language === \"ts\"\n ? {\n \"@types/node\": \"^24.6.0\",\n prettier: \"^3.6.2\",\n tsx: \"^4.20.5\",\n typescript: \"^5.9.2\",\n vitest: \"^2.1.9\",\n }\n : {\n prettier: \"^3.6.2\",\n vitest: \"^2.1.9\",\n },\n };\n\n return `${JSON.stringify(packageJson, null, 2)}\\n`;\n}\n\nfunction resourceBlock(capability: Capability, advanced: boolean): string {\n switch (capability) {\n case \"catalog\":\n return `catalog: {\n endpoints: [\n {\n id: \"top\",\n name: \"Top\",\n mediaTypes: [\"movie\"],\n filters: [{ key: \"genre\", valueType: \"string\" }],\n },\n ],\n handler: async () => ({\n items: [],\n }),\n },`;\n case \"meta\":\n return `meta: {\n mediaTypes: [\"movie\"],\n includes: [\"videos\", \"links\"],\n handler: async () => ({\n item: ${\n advanced\n ? `{\n summary: {\n id: { namespace: \"imdb\", value: \"tt1254207\" },\n mediaType: \"movie\",\n title: \"Big Buck Bunny\",\n links: [],\n },\n defaultVideoID: \"main\",\n trailers: [{ transport: { kind: \"youtube\", id: \"aqz-KE-bpKQ\" } }],\n videos: [\n {\n id: \"main\",\n title: \"Main\",\n streams: [{ transport: { kind: \"http\", url: \"https://example.com/video.mp4\" } }],\n },\n ],\n }`\n : \"null\"\n },\n }),\n },`;\n case \"stream\":\n return `stream: {\n mediaTypes: [\"movie\"],\n supportedTransports: ${advanced ? `[\"http\", \"torrent\", \"usenet\", \"archive\", \"youtube\"]` : `[\"http\"]`},\n handler: async () => ({\n streams: [\n {\n transport: { kind: \"http\", url: \"https://example.com/video.mp4\", mode: \"stream\" },\n hints: {\n notWebReady: true,\n proxyHeaders: { request: { \"User-Agent\": \"StreamFox\" } },\n },\n },\n${\n advanced\n ? ` {\n transport: { kind: \"torrent\", infoHash: \"abcdef\", peerDiscovery: [\"tracker:udp://tracker.example.com:80\"] },\n selection: { fileIndex: 0 },\n },\n {\n transport: { kind: \"usenet\", nzbURL: \"https://example.com/file.nzb\", servers: [\"nntps://user:pass@news.example.com:563/4\"] },\n },\n {\n transport: {\n kind: \"archive\",\n format: \"zip\",\n files: [{ url: \"https://example.com/archive.zip\", bytes: 1024 }],\n },\n selection: { fileMustInclude: \"movie.mkv\" },\n },\n`\n : \"\"\n} ],\n }),\n },`;\n case \"subtitles\":\n return `subtitles: {\n mediaTypes: [\"movie\", \"episode\"],\n defaultLanguages: [\"en\"],\n handler: async (request, { settings }) => {\n const configuredLanguages = Array.isArray(settings.languages)\n ? settings.languages\n : [];\n const languagePreferences =\n configuredLanguages.length > 0 ? configuredLanguages : (request.languagePreferences ?? []);\n\n void languagePreferences;\n void settings.includeHI;\n\n return {\n subtitles: [],\n };\n },\n },`;\n case \"plugin_catalog\":\n return `pluginCatalog: {\n endpoints: [\n {\n id: \"featured\",\n name: \"Featured\",\n pluginKinds: [\"catalog\", \"meta\", \"stream\", \"subtitles\"],\n tags: [\"official\"],\n },\n ],\n handler: async () => ({\n plugins: [\n {\n id: \"com.example.recommended\",\n name: \"Recommended\",\n version: \"1.0.0\",\n pluginKinds: [\"catalog\", \"meta\"],\n distribution: {\n transport: \"https\",\n manifestURL: \"https://plugins.example.com/recommended/manifest\",\n },\n manifestSnapshot: {\n plugin: { id: \"com.example.recommended\" },\n },\n },\n ],\n }),\n },`;\n default:\n return \"\";\n }\n}\n\nfunction makeInstallBlock(preset: Preset): string {\n if (preset !== \"subtitles\") {\n return \"\";\n }\n\n return ` install: {\n configurationRequired: true,\n title: \"Subtitle Settings\",\n description: \"Configure subtitle defaults before installing this plugin.\",\n fields: [\n settings.multiSelect(\"languages\", {\n label: \"Languages\",\n options: [\n { label: \"English\", value: \"en\" },\n { label: \"Greek\", value: \"el\" },\n { label: \"Spanish\", value: \"es\" },\n ],\n defaultValue: [\"en\"],\n }),\n settings.checkbox(\"includeHI\", {\n label: \"Include hearing impaired\",\n defaultValue: true,\n }),\n ],\n },\n`;\n}\n\nfunction makePluginFile(\n name: string,\n preset: Preset,\n capabilities: Capability[],\n advanced: boolean,\n): string {\n const resources = capabilities\n .map((capability) => resourceBlock(capability, advanced))\n .join(\"\\n \");\n const install = makeInstallBlock(preset);\n const importSpec =\n install.length > 0 ? \"definePlugin, settings\" : \"definePlugin\";\n const installBlock = install.length > 0 ? `${install}` : \"\";\n\n return `import { ${importSpec} } from \"@streamfox/plugin-sdk\";\n\nexport const plugin = definePlugin({\n plugin: {\n id: \"com.example.${name}\",\n name: \"${name}\",\n version: \"0.1.0\",\n description: \"Generated StreamFox plugin scaffold\",\n },\n${installBlock} resources: {\n ${resources}\n },\n});\n`;\n}\n\nfunction makeServerFile(language: Language): string {\n const pluginImport = language === \"ts\" ? \"./plugin\" : \"./plugin.js\";\n return `import { serve } from \"@streamfox/plugin-sdk\";\nimport { plugin } from \"${pluginImport}\";\n\nconst { url, installURL, launchURL } = await serve(plugin, {\n port: Number(process.env.PORT ?? 7000),\n integration: {\n installScheme: \"streamfox\",\n launchBaseURL: \"https://streamfox.app/#\",\n autoOpen: \"none\",\n },\n});\n\nconsole.log(\"Plugin manifest:\", url);\nconsole.log(\"Plugin installer deeplink:\", installURL);\nconsole.log(\"Plugin launch URL:\", launchURL);\n`;\n}\n\nfunction makeVitestFile(language: Language): string {\n const pluginImport = language === \"ts\" ? \"../src/plugin\" : \"../src/plugin.js\";\n return `import { describe, expect, it } from \"vitest\";\nimport { createServer } from \"@streamfox/plugin-sdk\";\nimport { plugin } from \"${pluginImport}\";\n\ndescribe(\"scaffold smoke\", () => {\n it(\"serves manifest and studio config\", async () => {\n const app = createServer(plugin, { frontend: false });\n\n const manifestResponse = await app.request(\"/manifest\");\n expect(manifestResponse.status).toBe(200);\n\n const studioResponse = await app.request(\"/studio-config\");\n expect(studioResponse.status).toBe(200);\n });\n});\n`;\n}\n\nconst tsConfig = `{\n \"compilerOptions\": {\n \"target\": \"ES2022\",\n \"module\": \"ESNext\",\n \"moduleResolution\": \"Bundler\",\n \"strict\": true,\n \"declaration\": true,\n \"outDir\": \"dist\",\n \"rootDir\": \"src\",\n \"types\": [\"node\"]\n },\n \"include\": [\"src\"]\n}\n`;\n\nconst prettierConfig = `{\n \"semi\": true,\n \"singleQuote\": false,\n \"trailingComma\": \"all\"\n}\n`;\n\nconst prettierIgnore = `dist\nnode_modules\n.DS_Store\n`;\n\nfunction makeReadme(\n projectName: string,\n preset: Preset,\n capabilities: Capability[],\n advanced: boolean,\n): string {\n const capabilitiesList = capabilities\n .map((capability) => `- ${capability}`)\n .join(\"\\n\");\n\n const endpointForCapability = (capability: Capability): string => {\n switch (capability) {\n case \"catalog\":\n return \"/catalog/:mediaType/:catalogID\";\n case \"meta\":\n return \"/meta/:mediaType/:itemID\";\n case \"stream\":\n return \"/stream/:mediaType/:itemID\";\n case \"subtitles\":\n return \"/subtitles/:mediaType/:itemID\";\n case \"plugin_catalog\":\n return \"/plugin_catalog/:catalogID/:pluginKind\";\n default:\n return `/${capability}`;\n }\n };\n\n const endpointLines = [\n \"- GET /manifest\",\n \"- GET /studio-config\",\n ...capabilities.map(\n (capability) => `- GET ${endpointForCapability(capability)}`,\n ),\n ].join(\"\\n\");\n\n return `# ${projectName}\n\nGenerated with create-streamfox-plugin.\n\nPreset: \\`${preset}\\`\nAdvanced template: \\`${advanced ? \"enabled\" : \"disabled\"}\\`\n\n## Scripts\n\n- npm run dev\n- npm run build\n- npm run format\n- npm run start\n- npm run test\n\n## Implemented Capabilities\n\n${capabilitiesList}\n\n## Stream Model\n\n- Unified transport model via \\`stream.transport\\`\n- Capability declaration via \\`resources.stream.supportedTransports\\`\n- Optional selection controls via \\`stream.selection\\`\n\n## Endpoints\n\n${endpointLines}\n`;\n}\n\nexport async function scaffoldProject(options: ScaffoldOptions): Promise<void> {\n const capabilities = sortedCapabilities([\n options.preset,\n ...(options.extraCapabilities ?? []),\n ]);\n const sdkVersion =\n (options.sdkVersion ?? DEFAULT_SDK_VERSION).trim() || DEFAULT_SDK_VERSION;\n const advanced = options.advanced ?? false;\n\n await ensureTargetDoesNotExist(options.targetDir);\n\n const srcDir = path.join(options.targetDir, \"src\");\n const testDir = path.join(options.targetDir, \"test\");\n\n await mkdir(srcDir, { recursive: true });\n await mkdir(testDir, { recursive: true });\n\n await writeFile(\n path.join(options.targetDir, \"package.json\"),\n makePackageJson(options.projectName, options.language, sdkVersion),\n );\n await writeFile(\n path.join(options.targetDir, \".prettierrc.json\"),\n prettierConfig,\n );\n await writeFile(\n path.join(options.targetDir, \".prettierignore\"),\n prettierIgnore,\n );\n await writeFile(\n path.join(options.targetDir, \"README.md\"),\n makeReadme(options.projectName, options.preset, capabilities, advanced),\n );\n\n if (options.language === \"ts\") {\n await writeFile(path.join(options.targetDir, \"tsconfig.json\"), tsConfig);\n await writeFile(\n path.join(srcDir, \"plugin.ts\"),\n makePluginFile(\n options.projectName,\n options.preset,\n capabilities,\n advanced,\n ),\n );\n await writeFile(path.join(srcDir, \"server.ts\"), makeServerFile(\"ts\"));\n await writeFile(path.join(testDir, \"plugin.test.ts\"), makeVitestFile(\"ts\"));\n } else {\n await writeFile(\n path.join(srcDir, \"plugin.js\"),\n makePluginFile(\n options.projectName,\n options.preset,\n capabilities,\n advanced,\n ),\n );\n await writeFile(path.join(srcDir, \"server.js\"), makeServerFile(\"js\"));\n await writeFile(path.join(testDir, \"plugin.test.js\"), makeVitestFile(\"js\"));\n }\n}\n"],"mappings":"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","names":["path","path"]}
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../package.json","../src/scaffold.ts"],"sourcesContent":["import path from \"node:path\";\nimport { Command, InvalidArgumentError } from \"commander\";\nimport prompts from \"prompts\";\nimport packageJSON from \"../package.json\";\nimport {\n CAPABILITIES,\n DEFAULT_PRESET,\n DEFAULT_SDK_VERSION,\n scaffoldProject,\n type Capability,\n type Language,\n type Preset,\n} from \"./scaffold\";\n\nfunction capabilitiesLabel(): string {\n return CAPABILITIES.join(\", \");\n}\n\nfunction parsePreset(input: string): Preset {\n if (CAPABILITIES.includes(input as Capability)) {\n return input as Preset;\n }\n throw new InvalidArgumentError(\n `Invalid preset '${input}'. Use one of: ${capabilitiesLabel()}`,\n );\n}\n\nfunction parseCapabilitiesList(input: string): Capability[] {\n const parsed = input\n .split(\",\")\n .map((value) => value.trim())\n .filter((value) => value.length > 0) as Capability[];\n\n for (const capability of parsed) {\n if (!CAPABILITIES.includes(capability)) {\n throw new InvalidArgumentError(\n `Invalid capability '${capability}'. Use one of: ${capabilitiesLabel()}`,\n );\n }\n }\n\n return Array.from(new Set(parsed));\n}\n\nconst program = new Command();\n\nprogram\n .name(\"create-streamfox-plugin\")\n .version(packageJSON.version, \"-v, --version\", \"display the current CLI version\")\n .description(\"Scaffold StreamFox plugin projects with modern JS/TS presets\")\n .showHelpAfterError()\n .argument(\"[directory]\", \"output directory\")\n .option(\"--ts\", \"use TypeScript template\")\n .option(\"--js\", \"use JavaScript template\")\n .option(\n \"--preset <preset>\",\n `plugin preset: ${capabilitiesLabel()}`,\n parsePreset,\n )\n .option(\n \"--capabilities <capabilities>\",\n \"extra capabilities as comma-separated list\",\n parseCapabilitiesList,\n )\n .option(\"--advanced\", \"generate advanced capability examples\")\n .option(\n \"--sdk-version <range>\",\n \"@streamfox/plugin-sdk version/range\",\n DEFAULT_SDK_VERSION,\n )\n .option(\"--yes\", \"skip prompts and use defaults\")\n .action(\n async (\n directoryArg: string | undefined,\n options: {\n ts?: boolean;\n js?: boolean;\n yes?: boolean;\n preset?: Preset;\n capabilities?: Capability[];\n advanced?: boolean;\n sdkVersion?: string;\n },\n ) => {\n if (options.ts && options.js) {\n throw new InvalidArgumentError(\"Choose either --ts or --js, not both.\");\n }\n\n const promptDefaults = {\n directory: directoryArg ?? \"my-media-plugin\",\n language: options.ts ? \"ts\" : options.js ? \"js\" : \"ts\",\n preset: options.preset ?? DEFAULT_PRESET,\n capabilities: Array.from(\n new Set([\n options.preset ?? DEFAULT_PRESET,\n ...(options.capabilities ?? []),\n ]),\n ) as Capability[],\n advanced: options.advanced ?? false,\n sdkVersion: options.sdkVersion ?? DEFAULT_SDK_VERSION,\n };\n\n const shouldPrompt = !options.yes;\n\n let directory = promptDefaults.directory;\n let language = promptDefaults.language as Language;\n let preset = promptDefaults.preset;\n let capabilities = promptDefaults.capabilities;\n let advanced = promptDefaults.advanced;\n let sdkVersion = promptDefaults.sdkVersion;\n\n if (shouldPrompt) {\n const answers = await prompts(\n [\n {\n type: \"text\",\n name: \"directory\",\n message: \"Project directory\",\n initial: directory,\n },\n {\n type: \"select\",\n name: \"language\",\n message: \"Template language\",\n choices: [\n { title: \"TypeScript\", value: \"ts\" },\n { title: \"JavaScript\", value: \"js\" },\n ],\n initial: language === \"ts\" ? 0 : 1,\n },\n {\n type: \"multiselect\",\n name: \"capabilities\",\n message: \"Plugin capabilities\",\n choices: CAPABILITIES.map((capability) => ({\n title: capability,\n value: capability,\n selected: capabilities.includes(capability),\n })),\n instructions: false,\n min: 1,\n hint: \"Space to select\",\n },\n {\n type: \"confirm\",\n name: \"advanced\",\n message: \"Generate advanced capability examples?\",\n initial: advanced,\n },\n {\n type: \"text\",\n name: \"sdkVersion\",\n message: \"SDK dependency version/range\",\n initial: sdkVersion,\n },\n ],\n {\n onCancel: () => {\n process.exit(1);\n },\n },\n );\n\n directory = answers.directory;\n language = answers.language;\n capabilities = (answers.capabilities ??\n promptDefaults.capabilities) as Capability[];\n preset =\n capabilities[0] ?? promptDefaults.preset;\n advanced = Boolean(answers.advanced ?? promptDefaults.advanced);\n sdkVersion = answers.sdkVersion ?? promptDefaults.sdkVersion;\n }\n\n const targetDir = path.resolve(process.cwd(), directory);\n const projectName = path.basename(targetDir);\n\n await scaffoldProject({\n targetDir,\n projectName,\n language,\n capabilities,\n preset,\n advanced,\n sdkVersion,\n });\n\n console.log(`Created ${projectName} at ${targetDir}`);\n console.log(\"Next steps:\");\n console.log(` cd ${directory}`);\n console.log(\" npm install\");\n console.log(\" npm run dev\");\n },\n );\n\nvoid program.parseAsync(process.argv).catch((error: unknown) => {\n const message = error instanceof Error ? error.message : String(error);\n console.error(`Error: ${message}`);\n process.exit(1);\n});\n","{\n \"name\": \"@streamfox/create-streamfox-plugin\",\n \"version\": \"0.3.1\",\n \"description\": \"Standalone CLI to scaffold StreamFox plugin projects\",\n \"type\": \"module\",\n \"bin\": {\n \"create-streamfox-plugin\": \"dist/cli.cjs\"\n },\n \"main\": \"./dist/index.cjs\",\n \"module\": \"./dist/index.js\",\n \"types\": \"./dist/index.d.ts\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.js\",\n \"require\": \"./dist/index.cjs\"\n }\n },\n \"files\": [\n \"dist\",\n \"README.md\"\n ],\n \"scripts\": {\n \"build\": \"tsup\",\n \"format\": \"prettier --write .\",\n \"format:check\": \"prettier --check .\",\n \"test\": \"vitest run\",\n \"typecheck\": \"tsc --noEmit\",\n \"check\": \"npm run format:check && npm run typecheck && npm test && npm run build\"\n },\n \"dependencies\": {\n \"commander\": \"^12.1.0\",\n \"prompts\": \"^2.4.2\"\n },\n \"devDependencies\": {\n \"@types/node\": \"^24.6.0\",\n \"@types/prompts\": \"^2.4.9\",\n \"prettier\": \"^3.6.2\",\n \"tsup\": \"^8.5.0\",\n \"typescript\": \"^5.9.2\",\n \"vitest\": \"^2.1.9\"\n },\n \"engines\": {\n \"node\": \">=20\"\n }\n}\n","import { access, mkdir, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\n\nexport const CAPABILITIES = [\n \"catalog\",\n \"meta\",\n \"stream\",\n \"subtitles\",\n \"plugin_catalog\",\n] as const;\nexport type Capability = (typeof CAPABILITIES)[number];\nexport type Preset = Capability;\nexport type Language = \"ts\" | \"js\";\nexport const DEFAULT_PRESET: Preset = \"meta\";\nexport const DEFAULT_SDK_VERSION = \"^0.2.0\";\n\nexport interface ScaffoldOptions {\n targetDir: string;\n projectName: string;\n language: Language;\n preset?: Preset;\n capabilities?: Capability[];\n advanced?: boolean;\n extraCapabilities?: Capability[];\n sdkVersion?: string;\n}\n\nfunction sortedCapabilities(values: Capability[]): Capability[] {\n const unique = Array.from(new Set(values));\n return CAPABILITIES.filter((capability) => unique.includes(capability));\n}\n\nasync function ensureTargetDoesNotExist(targetDir: string): Promise<void> {\n try {\n await access(targetDir);\n throw new Error(`Target directory already exists: ${targetDir}`);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n return;\n }\n throw error;\n }\n}\n\nfunction makePackageJson(\n name: string,\n language: Language,\n sdkVersion: string,\n): string {\n const scripts =\n language === \"ts\"\n ? {\n dev: \"tsx watch src/server.ts\",\n build: \"tsc -p tsconfig.json\",\n start: \"node dist/server.js\",\n test: \"vitest run\",\n typecheck: \"tsc --noEmit\",\n }\n : {\n dev: \"node --watch src/server.js\",\n build: 'echo \"No build step for JavaScript template\"',\n start: \"node src/server.js\",\n test: \"vitest run\",\n };\n\n const normalizedScripts = {\n ...scripts,\n check:\n language === \"ts\"\n ? \"npm run typecheck && npm test && npm run build\"\n : \"npm test && npm run build\",\n };\n\n const packageJson = {\n name,\n version: \"0.1.0\",\n private: true,\n type: \"module\",\n scripts: normalizedScripts,\n dependencies: {\n \"@streamfox/plugin-sdk\": sdkVersion,\n },\n devDependencies:\n language === \"ts\"\n ? {\n \"@types/node\": \"^24.6.0\",\n tsx: \"^4.20.5\",\n typescript: \"^5.9.2\",\n vitest: \"^2.1.9\",\n }\n : {\n vitest: \"^2.1.9\",\n },\n };\n\n return `${JSON.stringify(packageJson, null, 2)}\\n`;\n}\n\nfunction resourceBlock(capability: Capability, advanced: boolean): string {\n switch (capability) {\n case \"catalog\":\n return `catalog: {\n endpoints: [\n {\n id: \"top\",\n name: \"Top\",\n mediaTypes: [\"movie\"],\n filters: [{ key: \"genre\", valueType: \"string\" }],\n },\n ],\n handler: async () => ({\n items: [],\n }),\n },`;\n case \"meta\":\n return `meta: {\n mediaTypes: [\"movie\"],\n includes: [\"videos\", \"links\"],\n handler: async () => ({\n item: ${\n advanced\n ? `{\n summary: {\n id: { namespace: \"imdb\", value: \"tt1254207\" },\n mediaType: \"movie\",\n title: \"Big Buck Bunny\",\n links: [],\n },\n defaultVideoID: \"main\",\n trailers: [{ transport: { kind: \"youtube\", id: \"aqz-KE-bpKQ\" } }],\n videos: [\n {\n id: \"main\",\n title: \"Main\",\n streams: [{ transport: { kind: \"http\", url: \"https://example.com/video.mp4\" } }],\n },\n ],\n }`\n : \"null\"\n },\n }),\n },`;\n case \"stream\":\n return `stream: {\n mediaTypes: [\"movie\"],\n supportedTransports: ${advanced ? `[\"http\", \"torrent\", \"usenet\", \"archive\", \"youtube\"]` : `[\"http\"]`},\n handler: async () => ({\n streams: [\n {\n transport: { kind: \"http\", url: \"https://example.com/video.mp4\", mode: \"stream\" },\n hints: {\n notWebReady: true,\n proxyHeaders: { request: { \"User-Agent\": \"StreamFox\" } },\n },\n },\n${\n advanced\n ? ` {\n transport: { kind: \"torrent\", infoHash: \"abcdef\", peerDiscovery: [\"tracker:udp://tracker.example.com:80\"] },\n selection: { fileIndex: 0 },\n },\n {\n transport: { kind: \"usenet\", nzbURL: \"https://example.com/file.nzb\", servers: [\"nntps://user:pass@news.example.com:563/4\"] },\n },\n {\n transport: {\n kind: \"archive\",\n format: \"zip\",\n files: [{ url: \"https://example.com/archive.zip\", bytes: 1024 }],\n },\n selection: { fileMustInclude: \"movie.mkv\" },\n },\n`\n : \"\"\n} ],\n }),\n },`;\n case \"subtitles\":\n return `subtitles: {\n mediaTypes: [\"movie\", \"episode\"],\n defaultLanguages: [\"en\"],\n handler: async (request, { settings }) => {\n const configuredLanguages = Array.isArray(settings.languages)\n ? settings.languages\n : [];\n const languagePreferences =\n configuredLanguages.length > 0 ? configuredLanguages : (request.languagePreferences ?? []);\n\n void languagePreferences;\n void settings.includeHI;\n\n return {\n subtitles: [],\n };\n },\n },`;\n case \"plugin_catalog\":\n return `pluginCatalog: {\n endpoints: [\n {\n id: \"featured\",\n name: \"Featured\",\n pluginKinds: [\"catalog\", \"meta\", \"stream\", \"subtitles\"],\n tags: [\"official\"],\n },\n ],\n handler: async () => ({\n plugins: [\n {\n id: \"com.example.recommended\",\n name: \"Recommended\",\n version: \"1.0.0\",\n pluginKinds: [\"catalog\", \"meta\"],\n distribution: {\n transport: \"https\",\n manifestURL: \"https://plugins.example.com/recommended/manifest\",\n },\n manifestSnapshot: {\n plugin: { id: \"com.example.recommended\" },\n },\n },\n ],\n }),\n },`;\n default:\n return \"\";\n }\n}\n\nfunction makeInstallBlock(capabilities: Capability[]): string {\n if (!capabilities.includes(\"subtitles\")) {\n return \"\";\n }\n\n return ` install: {\n configurationRequired: true,\n title: \"Subtitle Settings\",\n description: \"Configure subtitle defaults before installing this plugin.\",\n fields: [\n settings.multiSelect(\"languages\", {\n label: \"Languages\",\n options: [\n { label: \"English\", value: \"en\" },\n { label: \"Greek\", value: \"el\" },\n { label: \"Spanish\", value: \"es\" },\n ],\n defaultValue: [\"en\"],\n }),\n settings.checkbox(\"includeHI\", {\n label: \"Include hearing impaired\",\n defaultValue: true,\n }),\n ],\n },\n`;\n}\n\nfunction makePluginFile(\n name: string,\n capabilities: Capability[],\n advanced: boolean,\n): string {\n const resources = capabilities\n .map((capability) => resourceBlock(capability, advanced))\n .join(\"\\n \");\n const install = makeInstallBlock(capabilities);\n const importSpec =\n install.length > 0 ? \"definePlugin, settings\" : \"definePlugin\";\n const installBlock = install.length > 0 ? `${install}` : \"\";\n\n return `import { ${importSpec} } from \"@streamfox/plugin-sdk\";\n\nexport const plugin = definePlugin({\n plugin: {\n id: \"com.example.${name}\",\n name: \"${name}\",\n version: \"0.1.0\",\n description: \"Generated StreamFox plugin scaffold\",\n },\n${installBlock} resources: {\n ${resources}\n },\n});\n`;\n}\n\nfunction makeServerFile(language: Language): string {\n const pluginImport = language === \"ts\" ? \"./plugin\" : \"./plugin.js\";\n return `import { serve } from \"@streamfox/plugin-sdk\";\nimport { plugin } from \"${pluginImport}\";\n\nconst { url, installURL, launchURL } = await serve(plugin, {\n port: Number(process.env.PORT ?? 7000),\n integration: {\n installScheme: \"streamfox\",\n launchBaseURL: \"https://streamfox.app/#\",\n autoOpen: \"none\",\n },\n});\n\nconsole.log(\"Plugin manifest:\", url);\nconsole.log(\"Plugin installer deeplink:\", installURL);\nconsole.log(\"Plugin launch URL:\", launchURL);\n`;\n}\n\nfunction makeVitestFile(language: Language): string {\n const pluginImport = language === \"ts\" ? \"../src/plugin\" : \"../src/plugin.js\";\n return `import { describe, expect, it } from \"vitest\";\nimport { createServer } from \"@streamfox/plugin-sdk\";\nimport { plugin } from \"${pluginImport}\";\n\ndescribe(\"scaffold smoke\", () => {\n it(\"serves manifest and studio config\", async () => {\n const app = createServer(plugin, { frontend: false });\n\n const manifestResponse = await app.request(\"/manifest\");\n expect(manifestResponse.status).toBe(200);\n\n const studioResponse = await app.request(\"/studio-config\");\n expect(studioResponse.status).toBe(200);\n });\n});\n`;\n}\n\nconst tsConfig = `{\n \"compilerOptions\": {\n \"target\": \"ES2022\",\n \"module\": \"ESNext\",\n \"moduleResolution\": \"Bundler\",\n \"strict\": true,\n \"declaration\": true,\n \"outDir\": \"dist\",\n \"rootDir\": \"src\",\n \"types\": [\"node\"]\n },\n \"include\": [\"src\"]\n}\n`;\n\nconst gitIgnore = `dist\nnode_modules\n.DS_Store\n.env\n.env.*\ncoverage\n`;\n\nfunction makeReadme(\n projectName: string,\n capabilities: Capability[],\n advanced: boolean,\n): string {\n const capabilitiesList = capabilities\n .map((capability) => `- ${capability}`)\n .join(\"\\n\");\n\n const endpointForCapability = (capability: Capability): string => {\n switch (capability) {\n case \"catalog\":\n return \"/catalog/:mediaType/:catalogID\";\n case \"meta\":\n return \"/meta/:mediaType/:itemID\";\n case \"stream\":\n return \"/stream/:mediaType/:itemID\";\n case \"subtitles\":\n return \"/subtitles/:mediaType/:itemID\";\n case \"plugin_catalog\":\n return \"/plugin_catalog/:catalogID/:pluginKind\";\n default:\n return `/${capability}`;\n }\n };\n\n const endpointLines = [\n \"- GET /manifest\",\n \"- GET /studio-config\",\n ...capabilities.map(\n (capability) => `- GET ${endpointForCapability(capability)}`,\n ),\n ].join(\"\\n\");\n\n return `# ${projectName}\n\nGenerated with create-streamfox-plugin.\n\nCapabilities: \\`${capabilities.join(\", \")}\\`\nAdvanced template: \\`${advanced ? \"enabled\" : \"disabled\"}\\`\n\n## Scripts\n\n- npm run dev\n- npm run build\n- npm run start\n- npm run test\n- npm run check\n\n## Implemented Capabilities\n\n${capabilitiesList}\n\n## Stream Model\n\n- Unified transport model via \\`stream.transport\\`\n- Capability declaration via \\`resources.stream.supportedTransports\\`\n- Optional selection controls via \\`stream.selection\\`\n\n## Endpoints\n\n${endpointLines}\n`;\n}\n\nexport async function scaffoldProject(options: ScaffoldOptions): Promise<void> {\n const capabilities = options.capabilities\n ? sortedCapabilities(options.capabilities)\n : sortedCapabilities([\n options.preset ?? DEFAULT_PRESET,\n ...(options.extraCapabilities ?? []),\n ]);\n const sdkVersion =\n (options.sdkVersion ?? DEFAULT_SDK_VERSION).trim() || DEFAULT_SDK_VERSION;\n const advanced = options.advanced ?? false;\n\n await ensureTargetDoesNotExist(options.targetDir);\n\n const srcDir = path.join(options.targetDir, \"src\");\n const testDir = path.join(options.targetDir, \"test\");\n\n await mkdir(srcDir, { recursive: true });\n await mkdir(testDir, { recursive: true });\n\n await writeFile(\n path.join(options.targetDir, \"package.json\"),\n makePackageJson(options.projectName, options.language, sdkVersion),\n );\n await writeFile(path.join(options.targetDir, \".gitignore\"), gitIgnore);\n await writeFile(\n path.join(options.targetDir, \"README.md\"),\n makeReadme(options.projectName, capabilities, advanced),\n );\n\n if (options.language === \"ts\") {\n await writeFile(path.join(options.targetDir, \"tsconfig.json\"), tsConfig);\n await writeFile(\n path.join(srcDir, \"plugin.ts\"),\n makePluginFile(\n options.projectName,\n capabilities,\n advanced,\n ),\n );\n await writeFile(path.join(srcDir, \"server.ts\"), makeServerFile(\"ts\"));\n await writeFile(path.join(testDir, \"plugin.test.ts\"), makeVitestFile(\"ts\"));\n } else {\n await writeFile(\n path.join(srcDir, \"plugin.js\"),\n makePluginFile(\n options.projectName,\n capabilities,\n advanced,\n ),\n );\n await writeFile(path.join(srcDir, \"server.js\"), makeServerFile(\"js\"));\n await writeFile(path.join(testDir, \"plugin.test.js\"), makeVitestFile(\"js\"));\n }\n}\n"],"mappings":"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","names":["path","path"]}
|
package/dist/index.cjs
CHANGED
|
@@ -69,22 +69,18 @@ function makePackageJson(name, language, sdkVersion) {
|
|
|
69
69
|
const scripts = language === "ts" ? {
|
|
70
70
|
dev: "tsx watch src/server.ts",
|
|
71
71
|
build: "tsc -p tsconfig.json",
|
|
72
|
-
format: "prettier --write .",
|
|
73
|
-
"format:check": "prettier --check .",
|
|
74
72
|
start: "node dist/server.js",
|
|
75
73
|
test: "vitest run",
|
|
76
74
|
typecheck: "tsc --noEmit"
|
|
77
75
|
} : {
|
|
78
76
|
dev: "node --watch src/server.js",
|
|
79
77
|
build: 'echo "No build step for JavaScript template"',
|
|
80
|
-
format: "prettier --write .",
|
|
81
|
-
"format:check": "prettier --check .",
|
|
82
78
|
start: "node src/server.js",
|
|
83
79
|
test: "vitest run"
|
|
84
80
|
};
|
|
85
81
|
const normalizedScripts = {
|
|
86
82
|
...scripts,
|
|
87
|
-
check: language === "ts" ? "npm run
|
|
83
|
+
check: language === "ts" ? "npm run typecheck && npm test && npm run build" : "npm test && npm run build"
|
|
88
84
|
};
|
|
89
85
|
const packageJson = {
|
|
90
86
|
name,
|
|
@@ -97,12 +93,10 @@ function makePackageJson(name, language, sdkVersion) {
|
|
|
97
93
|
},
|
|
98
94
|
devDependencies: language === "ts" ? {
|
|
99
95
|
"@types/node": "^24.6.0",
|
|
100
|
-
prettier: "^3.6.2",
|
|
101
96
|
tsx: "^4.20.5",
|
|
102
97
|
typescript: "^5.9.2",
|
|
103
98
|
vitest: "^2.1.9"
|
|
104
99
|
} : {
|
|
105
|
-
prettier: "^3.6.2",
|
|
106
100
|
vitest: "^2.1.9"
|
|
107
101
|
}
|
|
108
102
|
};
|
|
@@ -231,8 +225,8 @@ ${advanced ? ` {
|
|
|
231
225
|
return "";
|
|
232
226
|
}
|
|
233
227
|
}
|
|
234
|
-
function makeInstallBlock(
|
|
235
|
-
if (
|
|
228
|
+
function makeInstallBlock(capabilities) {
|
|
229
|
+
if (!capabilities.includes("subtitles")) {
|
|
236
230
|
return "";
|
|
237
231
|
}
|
|
238
232
|
return ` install: {
|
|
@@ -257,9 +251,9 @@ function makeInstallBlock(preset) {
|
|
|
257
251
|
},
|
|
258
252
|
`;
|
|
259
253
|
}
|
|
260
|
-
function makePluginFile(name,
|
|
254
|
+
function makePluginFile(name, capabilities, advanced) {
|
|
261
255
|
const resources = capabilities.map((capability) => resourceBlock(capability, advanced)).join("\n ");
|
|
262
|
-
const install = makeInstallBlock(
|
|
256
|
+
const install = makeInstallBlock(capabilities);
|
|
263
257
|
const importSpec = install.length > 0 ? "definePlugin, settings" : "definePlugin";
|
|
264
258
|
const installBlock = install.length > 0 ? `${install}` : "";
|
|
265
259
|
return `import { ${importSpec} } from "@streamfox/plugin-sdk";
|
|
@@ -329,17 +323,14 @@ var tsConfig = `{
|
|
|
329
323
|
"include": ["src"]
|
|
330
324
|
}
|
|
331
325
|
`;
|
|
332
|
-
var
|
|
333
|
-
"semi": true,
|
|
334
|
-
"singleQuote": false,
|
|
335
|
-
"trailingComma": "all"
|
|
336
|
-
}
|
|
337
|
-
`;
|
|
338
|
-
var prettierIgnore = `dist
|
|
326
|
+
var gitIgnore = `dist
|
|
339
327
|
node_modules
|
|
340
328
|
.DS_Store
|
|
329
|
+
.env
|
|
330
|
+
.env.*
|
|
331
|
+
coverage
|
|
341
332
|
`;
|
|
342
|
-
function makeReadme(projectName,
|
|
333
|
+
function makeReadme(projectName, capabilities, advanced) {
|
|
343
334
|
const capabilitiesList = capabilities.map((capability) => `- ${capability}`).join("\n");
|
|
344
335
|
const endpointForCapability = (capability) => {
|
|
345
336
|
switch (capability) {
|
|
@@ -368,16 +359,16 @@ function makeReadme(projectName, preset, capabilities, advanced) {
|
|
|
368
359
|
|
|
369
360
|
Generated with create-streamfox-plugin.
|
|
370
361
|
|
|
371
|
-
|
|
362
|
+
Capabilities: \`${capabilities.join(", ")}\`
|
|
372
363
|
Advanced template: \`${advanced ? "enabled" : "disabled"}\`
|
|
373
364
|
|
|
374
365
|
## Scripts
|
|
375
366
|
|
|
376
367
|
- npm run dev
|
|
377
368
|
- npm run build
|
|
378
|
-
- npm run format
|
|
379
369
|
- npm run start
|
|
380
370
|
- npm run test
|
|
371
|
+
- npm run check
|
|
381
372
|
|
|
382
373
|
## Implemented Capabilities
|
|
383
374
|
|
|
@@ -395,8 +386,8 @@ ${endpointLines}
|
|
|
395
386
|
`;
|
|
396
387
|
}
|
|
397
388
|
async function scaffoldProject(options) {
|
|
398
|
-
const capabilities = sortedCapabilities([
|
|
399
|
-
options.preset,
|
|
389
|
+
const capabilities = options.capabilities ? sortedCapabilities(options.capabilities) : sortedCapabilities([
|
|
390
|
+
options.preset ?? DEFAULT_PRESET,
|
|
400
391
|
...options.extraCapabilities ?? []
|
|
401
392
|
]);
|
|
402
393
|
const sdkVersion = (options.sdkVersion ?? DEFAULT_SDK_VERSION).trim() || DEFAULT_SDK_VERSION;
|
|
@@ -410,17 +401,10 @@ async function scaffoldProject(options) {
|
|
|
410
401
|
import_node_path.default.join(options.targetDir, "package.json"),
|
|
411
402
|
makePackageJson(options.projectName, options.language, sdkVersion)
|
|
412
403
|
);
|
|
413
|
-
await (0, import_promises.writeFile)(
|
|
414
|
-
import_node_path.default.join(options.targetDir, ".prettierrc.json"),
|
|
415
|
-
prettierConfig
|
|
416
|
-
);
|
|
417
|
-
await (0, import_promises.writeFile)(
|
|
418
|
-
import_node_path.default.join(options.targetDir, ".prettierignore"),
|
|
419
|
-
prettierIgnore
|
|
420
|
-
);
|
|
404
|
+
await (0, import_promises.writeFile)(import_node_path.default.join(options.targetDir, ".gitignore"), gitIgnore);
|
|
421
405
|
await (0, import_promises.writeFile)(
|
|
422
406
|
import_node_path.default.join(options.targetDir, "README.md"),
|
|
423
|
-
makeReadme(options.projectName,
|
|
407
|
+
makeReadme(options.projectName, capabilities, advanced)
|
|
424
408
|
);
|
|
425
409
|
if (options.language === "ts") {
|
|
426
410
|
await (0, import_promises.writeFile)(import_node_path.default.join(options.targetDir, "tsconfig.json"), tsConfig);
|
|
@@ -428,7 +412,6 @@ async function scaffoldProject(options) {
|
|
|
428
412
|
import_node_path.default.join(srcDir, "plugin.ts"),
|
|
429
413
|
makePluginFile(
|
|
430
414
|
options.projectName,
|
|
431
|
-
options.preset,
|
|
432
415
|
capabilities,
|
|
433
416
|
advanced
|
|
434
417
|
)
|
|
@@ -440,7 +423,6 @@ async function scaffoldProject(options) {
|
|
|
440
423
|
import_node_path.default.join(srcDir, "plugin.js"),
|
|
441
424
|
makePluginFile(
|
|
442
425
|
options.projectName,
|
|
443
|
-
options.preset,
|
|
444
426
|
capabilities,
|
|
445
427
|
advanced
|
|
446
428
|
)
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/scaffold.ts"],"sourcesContent":["export * from \"./scaffold\";\n","import { access, mkdir, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\n\nexport const CAPABILITIES = [\n \"catalog\",\n \"meta\",\n \"stream\",\n \"subtitles\",\n \"plugin_catalog\",\n] as const;\nexport type Capability = (typeof CAPABILITIES)[number];\nexport type Preset = Capability;\nexport type Language = \"ts\" | \"js\";\nexport const DEFAULT_PRESET: Preset = \"meta\";\nexport const DEFAULT_SDK_VERSION = \"^0.2.0\";\n\nexport interface ScaffoldOptions {\n targetDir: string;\n projectName: string;\n language: Language;\n preset: Preset;\n advanced?: boolean;\n extraCapabilities?: Capability[];\n sdkVersion?: string;\n}\n\nfunction sortedCapabilities(values: Capability[]): Capability[] {\n const unique = Array.from(new Set(values));\n return CAPABILITIES.filter((capability) => unique.includes(capability));\n}\n\nasync function ensureTargetDoesNotExist(targetDir: string): Promise<void> {\n try {\n await access(targetDir);\n throw new Error(`Target directory already exists: ${targetDir}`);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n return;\n }\n throw error;\n }\n}\n\nfunction makePackageJson(\n name: string,\n language: Language,\n sdkVersion: string,\n): string {\n const scripts =\n language === \"ts\"\n ? {\n dev: \"tsx watch src/server.ts\",\n build: \"tsc -p tsconfig.json\",\n format: \"prettier --write .\",\n \"format:check\": \"prettier --check .\",\n start: \"node dist/server.js\",\n test: \"vitest run\",\n typecheck: \"tsc --noEmit\",\n }\n : {\n dev: \"node --watch src/server.js\",\n build: 'echo \"No build step for JavaScript template\"',\n format: \"prettier --write .\",\n \"format:check\": \"prettier --check .\",\n start: \"node src/server.js\",\n test: \"vitest run\",\n };\n\n const normalizedScripts = {\n ...scripts,\n check:\n language === \"ts\"\n ? \"npm run format:check && npm run typecheck && npm test && npm run build\"\n : \"npm run format:check && npm test && npm run build\",\n };\n\n const packageJson = {\n name,\n version: \"0.1.0\",\n private: true,\n type: \"module\",\n scripts: normalizedScripts,\n dependencies: {\n \"@streamfox/plugin-sdk\": sdkVersion,\n },\n devDependencies:\n language === \"ts\"\n ? {\n \"@types/node\": \"^24.6.0\",\n prettier: \"^3.6.2\",\n tsx: \"^4.20.5\",\n typescript: \"^5.9.2\",\n vitest: \"^2.1.9\",\n }\n : {\n prettier: \"^3.6.2\",\n vitest: \"^2.1.9\",\n },\n };\n\n return `${JSON.stringify(packageJson, null, 2)}\\n`;\n}\n\nfunction resourceBlock(capability: Capability, advanced: boolean): string {\n switch (capability) {\n case \"catalog\":\n return `catalog: {\n endpoints: [\n {\n id: \"top\",\n name: \"Top\",\n mediaTypes: [\"movie\"],\n filters: [{ key: \"genre\", valueType: \"string\" }],\n },\n ],\n handler: async () => ({\n items: [],\n }),\n },`;\n case \"meta\":\n return `meta: {\n mediaTypes: [\"movie\"],\n includes: [\"videos\", \"links\"],\n handler: async () => ({\n item: ${\n advanced\n ? `{\n summary: {\n id: { namespace: \"imdb\", value: \"tt1254207\" },\n mediaType: \"movie\",\n title: \"Big Buck Bunny\",\n links: [],\n },\n defaultVideoID: \"main\",\n trailers: [{ transport: { kind: \"youtube\", id: \"aqz-KE-bpKQ\" } }],\n videos: [\n {\n id: \"main\",\n title: \"Main\",\n streams: [{ transport: { kind: \"http\", url: \"https://example.com/video.mp4\" } }],\n },\n ],\n }`\n : \"null\"\n },\n }),\n },`;\n case \"stream\":\n return `stream: {\n mediaTypes: [\"movie\"],\n supportedTransports: ${advanced ? `[\"http\", \"torrent\", \"usenet\", \"archive\", \"youtube\"]` : `[\"http\"]`},\n handler: async () => ({\n streams: [\n {\n transport: { kind: \"http\", url: \"https://example.com/video.mp4\", mode: \"stream\" },\n hints: {\n notWebReady: true,\n proxyHeaders: { request: { \"User-Agent\": \"StreamFox\" } },\n },\n },\n${\n advanced\n ? ` {\n transport: { kind: \"torrent\", infoHash: \"abcdef\", peerDiscovery: [\"tracker:udp://tracker.example.com:80\"] },\n selection: { fileIndex: 0 },\n },\n {\n transport: { kind: \"usenet\", nzbURL: \"https://example.com/file.nzb\", servers: [\"nntps://user:pass@news.example.com:563/4\"] },\n },\n {\n transport: {\n kind: \"archive\",\n format: \"zip\",\n files: [{ url: \"https://example.com/archive.zip\", bytes: 1024 }],\n },\n selection: { fileMustInclude: \"movie.mkv\" },\n },\n`\n : \"\"\n} ],\n }),\n },`;\n case \"subtitles\":\n return `subtitles: {\n mediaTypes: [\"movie\", \"episode\"],\n defaultLanguages: [\"en\"],\n handler: async (request, { settings }) => {\n const configuredLanguages = Array.isArray(settings.languages)\n ? settings.languages\n : [];\n const languagePreferences =\n configuredLanguages.length > 0 ? configuredLanguages : (request.languagePreferences ?? []);\n\n void languagePreferences;\n void settings.includeHI;\n\n return {\n subtitles: [],\n };\n },\n },`;\n case \"plugin_catalog\":\n return `pluginCatalog: {\n endpoints: [\n {\n id: \"featured\",\n name: \"Featured\",\n pluginKinds: [\"catalog\", \"meta\", \"stream\", \"subtitles\"],\n tags: [\"official\"],\n },\n ],\n handler: async () => ({\n plugins: [\n {\n id: \"com.example.recommended\",\n name: \"Recommended\",\n version: \"1.0.0\",\n pluginKinds: [\"catalog\", \"meta\"],\n distribution: {\n transport: \"https\",\n manifestURL: \"https://plugins.example.com/recommended/manifest\",\n },\n manifestSnapshot: {\n plugin: { id: \"com.example.recommended\" },\n },\n },\n ],\n }),\n },`;\n default:\n return \"\";\n }\n}\n\nfunction makeInstallBlock(preset: Preset): string {\n if (preset !== \"subtitles\") {\n return \"\";\n }\n\n return ` install: {\n configurationRequired: true,\n title: \"Subtitle Settings\",\n description: \"Configure subtitle defaults before installing this plugin.\",\n fields: [\n settings.multiSelect(\"languages\", {\n label: \"Languages\",\n options: [\n { label: \"English\", value: \"en\" },\n { label: \"Greek\", value: \"el\" },\n { label: \"Spanish\", value: \"es\" },\n ],\n defaultValue: [\"en\"],\n }),\n settings.checkbox(\"includeHI\", {\n label: \"Include hearing impaired\",\n defaultValue: true,\n }),\n ],\n },\n`;\n}\n\nfunction makePluginFile(\n name: string,\n preset: Preset,\n capabilities: Capability[],\n advanced: boolean,\n): string {\n const resources = capabilities\n .map((capability) => resourceBlock(capability, advanced))\n .join(\"\\n \");\n const install = makeInstallBlock(preset);\n const importSpec =\n install.length > 0 ? \"definePlugin, settings\" : \"definePlugin\";\n const installBlock = install.length > 0 ? `${install}` : \"\";\n\n return `import { ${importSpec} } from \"@streamfox/plugin-sdk\";\n\nexport const plugin = definePlugin({\n plugin: {\n id: \"com.example.${name}\",\n name: \"${name}\",\n version: \"0.1.0\",\n description: \"Generated StreamFox plugin scaffold\",\n },\n${installBlock} resources: {\n ${resources}\n },\n});\n`;\n}\n\nfunction makeServerFile(language: Language): string {\n const pluginImport = language === \"ts\" ? \"./plugin\" : \"./plugin.js\";\n return `import { serve } from \"@streamfox/plugin-sdk\";\nimport { plugin } from \"${pluginImport}\";\n\nconst { url, installURL, launchURL } = await serve(plugin, {\n port: Number(process.env.PORT ?? 7000),\n integration: {\n installScheme: \"streamfox\",\n launchBaseURL: \"https://streamfox.app/#\",\n autoOpen: \"none\",\n },\n});\n\nconsole.log(\"Plugin manifest:\", url);\nconsole.log(\"Plugin installer deeplink:\", installURL);\nconsole.log(\"Plugin launch URL:\", launchURL);\n`;\n}\n\nfunction makeVitestFile(language: Language): string {\n const pluginImport = language === \"ts\" ? \"../src/plugin\" : \"../src/plugin.js\";\n return `import { describe, expect, it } from \"vitest\";\nimport { createServer } from \"@streamfox/plugin-sdk\";\nimport { plugin } from \"${pluginImport}\";\n\ndescribe(\"scaffold smoke\", () => {\n it(\"serves manifest and studio config\", async () => {\n const app = createServer(plugin, { frontend: false });\n\n const manifestResponse = await app.request(\"/manifest\");\n expect(manifestResponse.status).toBe(200);\n\n const studioResponse = await app.request(\"/studio-config\");\n expect(studioResponse.status).toBe(200);\n });\n});\n`;\n}\n\nconst tsConfig = `{\n \"compilerOptions\": {\n \"target\": \"ES2022\",\n \"module\": \"ESNext\",\n \"moduleResolution\": \"Bundler\",\n \"strict\": true,\n \"declaration\": true,\n \"outDir\": \"dist\",\n \"rootDir\": \"src\",\n \"types\": [\"node\"]\n },\n \"include\": [\"src\"]\n}\n`;\n\nconst prettierConfig = `{\n \"semi\": true,\n \"singleQuote\": false,\n \"trailingComma\": \"all\"\n}\n`;\n\nconst prettierIgnore = `dist\nnode_modules\n.DS_Store\n`;\n\nfunction makeReadme(\n projectName: string,\n preset: Preset,\n capabilities: Capability[],\n advanced: boolean,\n): string {\n const capabilitiesList = capabilities\n .map((capability) => `- ${capability}`)\n .join(\"\\n\");\n\n const endpointForCapability = (capability: Capability): string => {\n switch (capability) {\n case \"catalog\":\n return \"/catalog/:mediaType/:catalogID\";\n case \"meta\":\n return \"/meta/:mediaType/:itemID\";\n case \"stream\":\n return \"/stream/:mediaType/:itemID\";\n case \"subtitles\":\n return \"/subtitles/:mediaType/:itemID\";\n case \"plugin_catalog\":\n return \"/plugin_catalog/:catalogID/:pluginKind\";\n default:\n return `/${capability}`;\n }\n };\n\n const endpointLines = [\n \"- GET /manifest\",\n \"- GET /studio-config\",\n ...capabilities.map(\n (capability) => `- GET ${endpointForCapability(capability)}`,\n ),\n ].join(\"\\n\");\n\n return `# ${projectName}\n\nGenerated with create-streamfox-plugin.\n\nPreset: \\`${preset}\\`\nAdvanced template: \\`${advanced ? \"enabled\" : \"disabled\"}\\`\n\n## Scripts\n\n- npm run dev\n- npm run build\n- npm run format\n- npm run start\n- npm run test\n\n## Implemented Capabilities\n\n${capabilitiesList}\n\n## Stream Model\n\n- Unified transport model via \\`stream.transport\\`\n- Capability declaration via \\`resources.stream.supportedTransports\\`\n- Optional selection controls via \\`stream.selection\\`\n\n## Endpoints\n\n${endpointLines}\n`;\n}\n\nexport async function scaffoldProject(options: ScaffoldOptions): Promise<void> {\n const capabilities = sortedCapabilities([\n options.preset,\n ...(options.extraCapabilities ?? []),\n ]);\n const sdkVersion =\n (options.sdkVersion ?? DEFAULT_SDK_VERSION).trim() || DEFAULT_SDK_VERSION;\n const advanced = options.advanced ?? false;\n\n await ensureTargetDoesNotExist(options.targetDir);\n\n const srcDir = path.join(options.targetDir, \"src\");\n const testDir = path.join(options.targetDir, \"test\");\n\n await mkdir(srcDir, { recursive: true });\n await mkdir(testDir, { recursive: true });\n\n await writeFile(\n path.join(options.targetDir, \"package.json\"),\n makePackageJson(options.projectName, options.language, sdkVersion),\n );\n await writeFile(\n path.join(options.targetDir, \".prettierrc.json\"),\n prettierConfig,\n );\n await writeFile(\n path.join(options.targetDir, \".prettierignore\"),\n prettierIgnore,\n );\n await writeFile(\n path.join(options.targetDir, \"README.md\"),\n makeReadme(options.projectName, options.preset, capabilities, advanced),\n );\n\n if (options.language === \"ts\") {\n await writeFile(path.join(options.targetDir, \"tsconfig.json\"), tsConfig);\n await writeFile(\n path.join(srcDir, \"plugin.ts\"),\n makePluginFile(\n options.projectName,\n options.preset,\n capabilities,\n advanced,\n ),\n );\n await writeFile(path.join(srcDir, \"server.ts\"), makeServerFile(\"ts\"));\n await writeFile(path.join(testDir, \"plugin.test.ts\"), makeVitestFile(\"ts\"));\n } else {\n await writeFile(\n path.join(srcDir, \"plugin.js\"),\n makePluginFile(\n options.projectName,\n options.preset,\n capabilities,\n advanced,\n ),\n );\n await writeFile(path.join(srcDir, \"server.js\"), makeServerFile(\"js\"));\n await writeFile(path.join(testDir, \"plugin.test.js\"), makeVitestFile(\"js\"));\n }\n}\n"],"mappings":"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","names":["path"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/scaffold.ts"],"sourcesContent":["export * from \"./scaffold\";\n","import { access, mkdir, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\n\nexport const CAPABILITIES = [\n \"catalog\",\n \"meta\",\n \"stream\",\n \"subtitles\",\n \"plugin_catalog\",\n] as const;\nexport type Capability = (typeof CAPABILITIES)[number];\nexport type Preset = Capability;\nexport type Language = \"ts\" | \"js\";\nexport const DEFAULT_PRESET: Preset = \"meta\";\nexport const DEFAULT_SDK_VERSION = \"^0.2.0\";\n\nexport interface ScaffoldOptions {\n targetDir: string;\n projectName: string;\n language: Language;\n preset?: Preset;\n capabilities?: Capability[];\n advanced?: boolean;\n extraCapabilities?: Capability[];\n sdkVersion?: string;\n}\n\nfunction sortedCapabilities(values: Capability[]): Capability[] {\n const unique = Array.from(new Set(values));\n return CAPABILITIES.filter((capability) => unique.includes(capability));\n}\n\nasync function ensureTargetDoesNotExist(targetDir: string): Promise<void> {\n try {\n await access(targetDir);\n throw new Error(`Target directory already exists: ${targetDir}`);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n return;\n }\n throw error;\n }\n}\n\nfunction makePackageJson(\n name: string,\n language: Language,\n sdkVersion: string,\n): string {\n const scripts =\n language === \"ts\"\n ? {\n dev: \"tsx watch src/server.ts\",\n build: \"tsc -p tsconfig.json\",\n start: \"node dist/server.js\",\n test: \"vitest run\",\n typecheck: \"tsc --noEmit\",\n }\n : {\n dev: \"node --watch src/server.js\",\n build: 'echo \"No build step for JavaScript template\"',\n start: \"node src/server.js\",\n test: \"vitest run\",\n };\n\n const normalizedScripts = {\n ...scripts,\n check:\n language === \"ts\"\n ? \"npm run typecheck && npm test && npm run build\"\n : \"npm test && npm run build\",\n };\n\n const packageJson = {\n name,\n version: \"0.1.0\",\n private: true,\n type: \"module\",\n scripts: normalizedScripts,\n dependencies: {\n \"@streamfox/plugin-sdk\": sdkVersion,\n },\n devDependencies:\n language === \"ts\"\n ? {\n \"@types/node\": \"^24.6.0\",\n tsx: \"^4.20.5\",\n typescript: \"^5.9.2\",\n vitest: \"^2.1.9\",\n }\n : {\n vitest: \"^2.1.9\",\n },\n };\n\n return `${JSON.stringify(packageJson, null, 2)}\\n`;\n}\n\nfunction resourceBlock(capability: Capability, advanced: boolean): string {\n switch (capability) {\n case \"catalog\":\n return `catalog: {\n endpoints: [\n {\n id: \"top\",\n name: \"Top\",\n mediaTypes: [\"movie\"],\n filters: [{ key: \"genre\", valueType: \"string\" }],\n },\n ],\n handler: async () => ({\n items: [],\n }),\n },`;\n case \"meta\":\n return `meta: {\n mediaTypes: [\"movie\"],\n includes: [\"videos\", \"links\"],\n handler: async () => ({\n item: ${\n advanced\n ? `{\n summary: {\n id: { namespace: \"imdb\", value: \"tt1254207\" },\n mediaType: \"movie\",\n title: \"Big Buck Bunny\",\n links: [],\n },\n defaultVideoID: \"main\",\n trailers: [{ transport: { kind: \"youtube\", id: \"aqz-KE-bpKQ\" } }],\n videos: [\n {\n id: \"main\",\n title: \"Main\",\n streams: [{ transport: { kind: \"http\", url: \"https://example.com/video.mp4\" } }],\n },\n ],\n }`\n : \"null\"\n },\n }),\n },`;\n case \"stream\":\n return `stream: {\n mediaTypes: [\"movie\"],\n supportedTransports: ${advanced ? `[\"http\", \"torrent\", \"usenet\", \"archive\", \"youtube\"]` : `[\"http\"]`},\n handler: async () => ({\n streams: [\n {\n transport: { kind: \"http\", url: \"https://example.com/video.mp4\", mode: \"stream\" },\n hints: {\n notWebReady: true,\n proxyHeaders: { request: { \"User-Agent\": \"StreamFox\" } },\n },\n },\n${\n advanced\n ? ` {\n transport: { kind: \"torrent\", infoHash: \"abcdef\", peerDiscovery: [\"tracker:udp://tracker.example.com:80\"] },\n selection: { fileIndex: 0 },\n },\n {\n transport: { kind: \"usenet\", nzbURL: \"https://example.com/file.nzb\", servers: [\"nntps://user:pass@news.example.com:563/4\"] },\n },\n {\n transport: {\n kind: \"archive\",\n format: \"zip\",\n files: [{ url: \"https://example.com/archive.zip\", bytes: 1024 }],\n },\n selection: { fileMustInclude: \"movie.mkv\" },\n },\n`\n : \"\"\n} ],\n }),\n },`;\n case \"subtitles\":\n return `subtitles: {\n mediaTypes: [\"movie\", \"episode\"],\n defaultLanguages: [\"en\"],\n handler: async (request, { settings }) => {\n const configuredLanguages = Array.isArray(settings.languages)\n ? settings.languages\n : [];\n const languagePreferences =\n configuredLanguages.length > 0 ? configuredLanguages : (request.languagePreferences ?? []);\n\n void languagePreferences;\n void settings.includeHI;\n\n return {\n subtitles: [],\n };\n },\n },`;\n case \"plugin_catalog\":\n return `pluginCatalog: {\n endpoints: [\n {\n id: \"featured\",\n name: \"Featured\",\n pluginKinds: [\"catalog\", \"meta\", \"stream\", \"subtitles\"],\n tags: [\"official\"],\n },\n ],\n handler: async () => ({\n plugins: [\n {\n id: \"com.example.recommended\",\n name: \"Recommended\",\n version: \"1.0.0\",\n pluginKinds: [\"catalog\", \"meta\"],\n distribution: {\n transport: \"https\",\n manifestURL: \"https://plugins.example.com/recommended/manifest\",\n },\n manifestSnapshot: {\n plugin: { id: \"com.example.recommended\" },\n },\n },\n ],\n }),\n },`;\n default:\n return \"\";\n }\n}\n\nfunction makeInstallBlock(capabilities: Capability[]): string {\n if (!capabilities.includes(\"subtitles\")) {\n return \"\";\n }\n\n return ` install: {\n configurationRequired: true,\n title: \"Subtitle Settings\",\n description: \"Configure subtitle defaults before installing this plugin.\",\n fields: [\n settings.multiSelect(\"languages\", {\n label: \"Languages\",\n options: [\n { label: \"English\", value: \"en\" },\n { label: \"Greek\", value: \"el\" },\n { label: \"Spanish\", value: \"es\" },\n ],\n defaultValue: [\"en\"],\n }),\n settings.checkbox(\"includeHI\", {\n label: \"Include hearing impaired\",\n defaultValue: true,\n }),\n ],\n },\n`;\n}\n\nfunction makePluginFile(\n name: string,\n capabilities: Capability[],\n advanced: boolean,\n): string {\n const resources = capabilities\n .map((capability) => resourceBlock(capability, advanced))\n .join(\"\\n \");\n const install = makeInstallBlock(capabilities);\n const importSpec =\n install.length > 0 ? \"definePlugin, settings\" : \"definePlugin\";\n const installBlock = install.length > 0 ? `${install}` : \"\";\n\n return `import { ${importSpec} } from \"@streamfox/plugin-sdk\";\n\nexport const plugin = definePlugin({\n plugin: {\n id: \"com.example.${name}\",\n name: \"${name}\",\n version: \"0.1.0\",\n description: \"Generated StreamFox plugin scaffold\",\n },\n${installBlock} resources: {\n ${resources}\n },\n});\n`;\n}\n\nfunction makeServerFile(language: Language): string {\n const pluginImport = language === \"ts\" ? \"./plugin\" : \"./plugin.js\";\n return `import { serve } from \"@streamfox/plugin-sdk\";\nimport { plugin } from \"${pluginImport}\";\n\nconst { url, installURL, launchURL } = await serve(plugin, {\n port: Number(process.env.PORT ?? 7000),\n integration: {\n installScheme: \"streamfox\",\n launchBaseURL: \"https://streamfox.app/#\",\n autoOpen: \"none\",\n },\n});\n\nconsole.log(\"Plugin manifest:\", url);\nconsole.log(\"Plugin installer deeplink:\", installURL);\nconsole.log(\"Plugin launch URL:\", launchURL);\n`;\n}\n\nfunction makeVitestFile(language: Language): string {\n const pluginImport = language === \"ts\" ? \"../src/plugin\" : \"../src/plugin.js\";\n return `import { describe, expect, it } from \"vitest\";\nimport { createServer } from \"@streamfox/plugin-sdk\";\nimport { plugin } from \"${pluginImport}\";\n\ndescribe(\"scaffold smoke\", () => {\n it(\"serves manifest and studio config\", async () => {\n const app = createServer(plugin, { frontend: false });\n\n const manifestResponse = await app.request(\"/manifest\");\n expect(manifestResponse.status).toBe(200);\n\n const studioResponse = await app.request(\"/studio-config\");\n expect(studioResponse.status).toBe(200);\n });\n});\n`;\n}\n\nconst tsConfig = `{\n \"compilerOptions\": {\n \"target\": \"ES2022\",\n \"module\": \"ESNext\",\n \"moduleResolution\": \"Bundler\",\n \"strict\": true,\n \"declaration\": true,\n \"outDir\": \"dist\",\n \"rootDir\": \"src\",\n \"types\": [\"node\"]\n },\n \"include\": [\"src\"]\n}\n`;\n\nconst gitIgnore = `dist\nnode_modules\n.DS_Store\n.env\n.env.*\ncoverage\n`;\n\nfunction makeReadme(\n projectName: string,\n capabilities: Capability[],\n advanced: boolean,\n): string {\n const capabilitiesList = capabilities\n .map((capability) => `- ${capability}`)\n .join(\"\\n\");\n\n const endpointForCapability = (capability: Capability): string => {\n switch (capability) {\n case \"catalog\":\n return \"/catalog/:mediaType/:catalogID\";\n case \"meta\":\n return \"/meta/:mediaType/:itemID\";\n case \"stream\":\n return \"/stream/:mediaType/:itemID\";\n case \"subtitles\":\n return \"/subtitles/:mediaType/:itemID\";\n case \"plugin_catalog\":\n return \"/plugin_catalog/:catalogID/:pluginKind\";\n default:\n return `/${capability}`;\n }\n };\n\n const endpointLines = [\n \"- GET /manifest\",\n \"- GET /studio-config\",\n ...capabilities.map(\n (capability) => `- GET ${endpointForCapability(capability)}`,\n ),\n ].join(\"\\n\");\n\n return `# ${projectName}\n\nGenerated with create-streamfox-plugin.\n\nCapabilities: \\`${capabilities.join(\", \")}\\`\nAdvanced template: \\`${advanced ? \"enabled\" : \"disabled\"}\\`\n\n## Scripts\n\n- npm run dev\n- npm run build\n- npm run start\n- npm run test\n- npm run check\n\n## Implemented Capabilities\n\n${capabilitiesList}\n\n## Stream Model\n\n- Unified transport model via \\`stream.transport\\`\n- Capability declaration via \\`resources.stream.supportedTransports\\`\n- Optional selection controls via \\`stream.selection\\`\n\n## Endpoints\n\n${endpointLines}\n`;\n}\n\nexport async function scaffoldProject(options: ScaffoldOptions): Promise<void> {\n const capabilities = options.capabilities\n ? sortedCapabilities(options.capabilities)\n : sortedCapabilities([\n options.preset ?? DEFAULT_PRESET,\n ...(options.extraCapabilities ?? []),\n ]);\n const sdkVersion =\n (options.sdkVersion ?? DEFAULT_SDK_VERSION).trim() || DEFAULT_SDK_VERSION;\n const advanced = options.advanced ?? false;\n\n await ensureTargetDoesNotExist(options.targetDir);\n\n const srcDir = path.join(options.targetDir, \"src\");\n const testDir = path.join(options.targetDir, \"test\");\n\n await mkdir(srcDir, { recursive: true });\n await mkdir(testDir, { recursive: true });\n\n await writeFile(\n path.join(options.targetDir, \"package.json\"),\n makePackageJson(options.projectName, options.language, sdkVersion),\n );\n await writeFile(path.join(options.targetDir, \".gitignore\"), gitIgnore);\n await writeFile(\n path.join(options.targetDir, \"README.md\"),\n makeReadme(options.projectName, capabilities, advanced),\n );\n\n if (options.language === \"ts\") {\n await writeFile(path.join(options.targetDir, \"tsconfig.json\"), tsConfig);\n await writeFile(\n path.join(srcDir, \"plugin.ts\"),\n makePluginFile(\n options.projectName,\n capabilities,\n advanced,\n ),\n );\n await writeFile(path.join(srcDir, \"server.ts\"), makeServerFile(\"ts\"));\n await writeFile(path.join(testDir, \"plugin.test.ts\"), makeVitestFile(\"ts\"));\n } else {\n await writeFile(\n path.join(srcDir, \"plugin.js\"),\n makePluginFile(\n options.projectName,\n capabilities,\n advanced,\n ),\n );\n await writeFile(path.join(srcDir, \"server.js\"), makeServerFile(\"js\"));\n await writeFile(path.join(testDir, \"plugin.test.js\"), makeVitestFile(\"js\"));\n }\n}\n"],"mappings":"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","names":["path"]}
|
package/dist/index.d.cts
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -31,22 +31,18 @@ function makePackageJson(name, language, sdkVersion) {
|
|
|
31
31
|
const scripts = language === "ts" ? {
|
|
32
32
|
dev: "tsx watch src/server.ts",
|
|
33
33
|
build: "tsc -p tsconfig.json",
|
|
34
|
-
format: "prettier --write .",
|
|
35
|
-
"format:check": "prettier --check .",
|
|
36
34
|
start: "node dist/server.js",
|
|
37
35
|
test: "vitest run",
|
|
38
36
|
typecheck: "tsc --noEmit"
|
|
39
37
|
} : {
|
|
40
38
|
dev: "node --watch src/server.js",
|
|
41
39
|
build: 'echo "No build step for JavaScript template"',
|
|
42
|
-
format: "prettier --write .",
|
|
43
|
-
"format:check": "prettier --check .",
|
|
44
40
|
start: "node src/server.js",
|
|
45
41
|
test: "vitest run"
|
|
46
42
|
};
|
|
47
43
|
const normalizedScripts = {
|
|
48
44
|
...scripts,
|
|
49
|
-
check: language === "ts" ? "npm run
|
|
45
|
+
check: language === "ts" ? "npm run typecheck && npm test && npm run build" : "npm test && npm run build"
|
|
50
46
|
};
|
|
51
47
|
const packageJson = {
|
|
52
48
|
name,
|
|
@@ -59,12 +55,10 @@ function makePackageJson(name, language, sdkVersion) {
|
|
|
59
55
|
},
|
|
60
56
|
devDependencies: language === "ts" ? {
|
|
61
57
|
"@types/node": "^24.6.0",
|
|
62
|
-
prettier: "^3.6.2",
|
|
63
58
|
tsx: "^4.20.5",
|
|
64
59
|
typescript: "^5.9.2",
|
|
65
60
|
vitest: "^2.1.9"
|
|
66
61
|
} : {
|
|
67
|
-
prettier: "^3.6.2",
|
|
68
62
|
vitest: "^2.1.9"
|
|
69
63
|
}
|
|
70
64
|
};
|
|
@@ -193,8 +187,8 @@ ${advanced ? ` {
|
|
|
193
187
|
return "";
|
|
194
188
|
}
|
|
195
189
|
}
|
|
196
|
-
function makeInstallBlock(
|
|
197
|
-
if (
|
|
190
|
+
function makeInstallBlock(capabilities) {
|
|
191
|
+
if (!capabilities.includes("subtitles")) {
|
|
198
192
|
return "";
|
|
199
193
|
}
|
|
200
194
|
return ` install: {
|
|
@@ -219,9 +213,9 @@ function makeInstallBlock(preset) {
|
|
|
219
213
|
},
|
|
220
214
|
`;
|
|
221
215
|
}
|
|
222
|
-
function makePluginFile(name,
|
|
216
|
+
function makePluginFile(name, capabilities, advanced) {
|
|
223
217
|
const resources = capabilities.map((capability) => resourceBlock(capability, advanced)).join("\n ");
|
|
224
|
-
const install = makeInstallBlock(
|
|
218
|
+
const install = makeInstallBlock(capabilities);
|
|
225
219
|
const importSpec = install.length > 0 ? "definePlugin, settings" : "definePlugin";
|
|
226
220
|
const installBlock = install.length > 0 ? `${install}` : "";
|
|
227
221
|
return `import { ${importSpec} } from "@streamfox/plugin-sdk";
|
|
@@ -291,17 +285,14 @@ var tsConfig = `{
|
|
|
291
285
|
"include": ["src"]
|
|
292
286
|
}
|
|
293
287
|
`;
|
|
294
|
-
var
|
|
295
|
-
"semi": true,
|
|
296
|
-
"singleQuote": false,
|
|
297
|
-
"trailingComma": "all"
|
|
298
|
-
}
|
|
299
|
-
`;
|
|
300
|
-
var prettierIgnore = `dist
|
|
288
|
+
var gitIgnore = `dist
|
|
301
289
|
node_modules
|
|
302
290
|
.DS_Store
|
|
291
|
+
.env
|
|
292
|
+
.env.*
|
|
293
|
+
coverage
|
|
303
294
|
`;
|
|
304
|
-
function makeReadme(projectName,
|
|
295
|
+
function makeReadme(projectName, capabilities, advanced) {
|
|
305
296
|
const capabilitiesList = capabilities.map((capability) => `- ${capability}`).join("\n");
|
|
306
297
|
const endpointForCapability = (capability) => {
|
|
307
298
|
switch (capability) {
|
|
@@ -330,16 +321,16 @@ function makeReadme(projectName, preset, capabilities, advanced) {
|
|
|
330
321
|
|
|
331
322
|
Generated with create-streamfox-plugin.
|
|
332
323
|
|
|
333
|
-
|
|
324
|
+
Capabilities: \`${capabilities.join(", ")}\`
|
|
334
325
|
Advanced template: \`${advanced ? "enabled" : "disabled"}\`
|
|
335
326
|
|
|
336
327
|
## Scripts
|
|
337
328
|
|
|
338
329
|
- npm run dev
|
|
339
330
|
- npm run build
|
|
340
|
-
- npm run format
|
|
341
331
|
- npm run start
|
|
342
332
|
- npm run test
|
|
333
|
+
- npm run check
|
|
343
334
|
|
|
344
335
|
## Implemented Capabilities
|
|
345
336
|
|
|
@@ -357,8 +348,8 @@ ${endpointLines}
|
|
|
357
348
|
`;
|
|
358
349
|
}
|
|
359
350
|
async function scaffoldProject(options) {
|
|
360
|
-
const capabilities = sortedCapabilities([
|
|
361
|
-
options.preset,
|
|
351
|
+
const capabilities = options.capabilities ? sortedCapabilities(options.capabilities) : sortedCapabilities([
|
|
352
|
+
options.preset ?? DEFAULT_PRESET,
|
|
362
353
|
...options.extraCapabilities ?? []
|
|
363
354
|
]);
|
|
364
355
|
const sdkVersion = (options.sdkVersion ?? DEFAULT_SDK_VERSION).trim() || DEFAULT_SDK_VERSION;
|
|
@@ -372,17 +363,10 @@ async function scaffoldProject(options) {
|
|
|
372
363
|
path.join(options.targetDir, "package.json"),
|
|
373
364
|
makePackageJson(options.projectName, options.language, sdkVersion)
|
|
374
365
|
);
|
|
375
|
-
await writeFile(
|
|
376
|
-
path.join(options.targetDir, ".prettierrc.json"),
|
|
377
|
-
prettierConfig
|
|
378
|
-
);
|
|
379
|
-
await writeFile(
|
|
380
|
-
path.join(options.targetDir, ".prettierignore"),
|
|
381
|
-
prettierIgnore
|
|
382
|
-
);
|
|
366
|
+
await writeFile(path.join(options.targetDir, ".gitignore"), gitIgnore);
|
|
383
367
|
await writeFile(
|
|
384
368
|
path.join(options.targetDir, "README.md"),
|
|
385
|
-
makeReadme(options.projectName,
|
|
369
|
+
makeReadme(options.projectName, capabilities, advanced)
|
|
386
370
|
);
|
|
387
371
|
if (options.language === "ts") {
|
|
388
372
|
await writeFile(path.join(options.targetDir, "tsconfig.json"), tsConfig);
|
|
@@ -390,7 +374,6 @@ async function scaffoldProject(options) {
|
|
|
390
374
|
path.join(srcDir, "plugin.ts"),
|
|
391
375
|
makePluginFile(
|
|
392
376
|
options.projectName,
|
|
393
|
-
options.preset,
|
|
394
377
|
capabilities,
|
|
395
378
|
advanced
|
|
396
379
|
)
|
|
@@ -402,7 +385,6 @@ async function scaffoldProject(options) {
|
|
|
402
385
|
path.join(srcDir, "plugin.js"),
|
|
403
386
|
makePluginFile(
|
|
404
387
|
options.projectName,
|
|
405
|
-
options.preset,
|
|
406
388
|
capabilities,
|
|
407
389
|
advanced
|
|
408
390
|
)
|