#!/usr/bin/env node import * as NodeModule from "node:module"; import { fromYaml } from "@t3tools/shared/schemaYaml";import { HostProcessPlatform } from "@t3tools/shared/hostProcess";import { clerkFrontendApiHostnameFromPublishableKey } from "@t3tools/shared/relayAuth";import { resolveSpawnCommand } from "@t3tools/shared/shell";import rootPackageJson from "../package.json" with { type: "json" };import desktopPackageJson from "../apps/desktop/package.json" with { type: "json" };import serverPackageJson from "../apps/server/package.json" with { type: "json" }; import { BRAND_ASSET_PATHS } from "./lib/brand-assets.ts";import { getDefaultBuildArch } from "./lib/build-target-arch.ts";import { loadRepoEnv } from "./lib/public-config.ts";import { resolveCatalogDependencies } from "./lib/resolve-catalog.ts"; import * as NodeRuntime from "@effect/platform-node/NodeRuntime";import * as NodeServices from "@effect/platform-node/NodeServices";import * as Config from "effect/Config";import * as Data from "effect/Data";import * as Effect from "effect/Effect";import * as FileSystem from "effect/FileSystem";import * as Layer from "effect/Layer";import * as Logger from "effect/Logger";import * as Option from "effect/Option";import * as Path from "effect/Path";import * as Schema from "effect/Schema";import * as Stream from "effect/Stream";import { Command, Flag } from "effect/unstable/cli";import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"; const LINUX_ICON_SIZES = [16, 22, 24, 32, 48, 64, 128, 256, 512] as const;const DESKTOP_APP_ID = "com.t3tools.t3code";const APPLE_TEAM_ID_PATTERN = /^[A-Z0-9]{10}$/u; const BuildPlatform = Schema.Literals(["mac", "linux", "win"]);const BuildArch = Schema.Literals(["arm64", "x64", "universal"]); const WorkspaceConfig = Schema.Struct({ catalog: Schema.optional(Schema.Record(Schema.String, Schema.String)), overrides: Schema.optional(Schema.Record(Schema.String, Schema.String)), patchedDependencies: Schema.optional(Schema.Record(Schema.String, Schema.String)),});type WorkspaceConfig = typeof WorkspaceConfig.Type; const StageWorkspaceConfig = Schema.Struct({ supportedArchitectures: Schema.Struct({ os: Schema.Array(Schema.String), cpu: Schema.Array(Schema.String), }),}); const RepoRoot = Effect.service(Path.Path).pipe( Effect.flatMap((path) => path.fromFileUrl(new URL("..", import.meta.url))),);const encodeJsonString = Schema.encodeEffect(Schema.UnknownFromJsonString);const decodeWorkspaceConfig = Schema.decodeEffect(fromYaml(WorkspaceConfig));const encodeStageWorkspaceConfig = Schema.encodeEffect(fromYaml(StageWorkspaceConfig)); const readWorkspaceConfig = Effect.fn("readWorkspaceConfig")(function* () { const fs = yield* FileSystem.FileSystem; const path = yield* Path.Path; const repoRoot = yield* RepoRoot; const workspaceYaml = yield* fs.readFileString(path.join(repoRoot, "pnpm-workspace.yaml")); return yield* decodeWorkspaceConfig(workspaceYaml);}); interface DesktopBuildIconAssets { readonly macIconPng: string; readonly linuxIconPng: string; readonly windowsIconIco: string;} interface PlatformConfig { readonly cliFlag: "--mac" | "--linux" | "--win"; readonly defaultTarget: string; readonly archChoices: ReadonlyArray<typeof BuildArch.Type>;} const PLATFORM_CONFIG: Record<typeof BuildPlatform.Type, PlatformConfig> = { mac: { cliFlag: "--mac", defaultTarget: "dmg", archChoices: ["arm64", "x64", "universal"], }, linux: { cliFlag: "--linux", defaultTarget: "AppImage", archChoices: ["x64", "arm64"], }, win: { cliFlag: "--win", defaultTarget: "nsis", archChoices: ["x64", "arm64"], },}; interface BuildCliInput { readonly platform: Option.Option<typeof BuildPlatform.Type>; readonly target: Option.Option<string>; readonly arch: Option.Option<typeof BuildArch.Type>; readonly buildVersion: Option.Option<string>; readonly outputDir: Option.Option<string>; readonly skipBuild: Option.Option<boolean>; readonly keepStage: Option.Option<boolean>; readonly signed: Option.Option<boolean>; readonly verbose: Option.Option<boolean>; readonly mockUpdates: Option.Option<boolean>; readonly mockUpdateServerPort: Option.Option<number>;} function detectHostBuildPlatform(hostPlatform: string): typeof BuildPlatform.Type | undefined { if (hostPlatform === "darwin") return "mac"; if (hostPlatform === "linux") return "linux"; if (hostPlatform === "win32") return "win"; return undefined;} const getDefaultArch = Effect.fn("getDefaultArch")(function* (platform: typeof BuildPlatform.Type) { const config = PLATFORM_CONFIG[platform]; if (!config) { return "x64"; } return yield* getDefaultBuildArch(platform, config);}); export class BuildScriptError extends Data.TaggedError("BuildScriptError")<{ readonly message: string; readonly cause?: unknown;}> { static fromMacPasskeySigningConfiguration( cause: unknown, ): MacPasskeySigningConfigurationError | BuildScriptError { return isMacPasskeySigningConfigurationError(cause) ? cause : new BuildScriptError({ message: "Failed to resolve macOS passkey signing configuration.", cause, }); }} const collectStreamAsString = <E>(stream: Stream.Stream<Uint8Array, E>): Effect.Effect<string, E> => stream.pipe( Stream.decodeText(), Stream.runFold( () => "", (acc, chunk) => acc + chunk, ), ); const COMMAND_OUTPUT_TAIL_LENGTH = 20_000; function appendOutputTail(acc: string, chunk: string): string { const next = acc + chunk; return next.length > COMMAND_OUTPUT_TAIL_LENGTH ? next.slice(-COMMAND_OUTPUT_TAIL_LENGTH) : next;} function formatOutputSection(label: string, output: string): string | undefined { const trimmed = output.trim(); if (!trimmed) return undefined; return `${label} tail:\n${trimmed}`;} const collectCommandStream = <E>( stream: Stream.Stream<Uint8Array, E>, output: NodeJS.WriteStream, verbose: boolean,): Effect.Effect<string, E> => stream.pipe( Stream.decodeText(), Stream.runFoldEffect( () => "", (acc, chunk) => Effect.as( verbose ? Effect.sync(() => output.write(chunk)) : Effect.void, appendOutputTail(acc, chunk), ), ), ); const spawnAndCollectOutput = Effect.fn("spawnAndCollectOutput")(function* ( command: ChildProcess.Command,) { const spawner = yield* ChildProcessSpawner.ChildProcessSpawner; const child = yield* spawner.spawn(command); const [stdout, stderr, exitCode] = yield* Effect.all( [ collectStreamAsString(child.stdout), collectStreamAsString(child.stderr), child.exitCode.pipe(Effect.map(Number)), ], { concurrency: "unbounded" }, ); return { stdout, stderr, exitCode } as const;}); const resolveGitCommitHash = Effect.fn("resolveGitCommitHash")(function* (repoRoot: string) { const result = yield* spawnAndCollectOutput( ChildProcess.make("git", ["rev-parse", "--short=12", "HEAD"], { cwd: repoRoot, }), ).pipe( Effect.orElseSucceed(() => ({ stdout: "", stderr: "", exitCode: 1, })), ); if (result.exitCode !== 0) { return "unknown"; } const hash = result.stdout.trim(); if (!/^[0-9a-f]{7,40}$/i.test(hash)) { return "unknown"; } return hash.toLowerCase();}); const resolvePythonForNodeGyp = Effect.fn("resolvePythonForNodeGyp")(function* () { const fs = yield* FileSystem.FileSystem; const path = yield* Path.Path; const hostPlatform = yield* HostProcessPlatform; const env = yield* Config.all({ configuredPython: Config.string("npm_config_python").pipe( Config.orElse(() => Config.string("PYTHON")), Config.option, ), localAppData: Config.string("LOCALAPPDATA").pipe(Config.option), }); const configured = Option.getOrUndefined(env.configuredPython); if (configured && (yield* fs.exists(configured))) { return configured; } if (hostPlatform === "win32") { const localAppData = Option.getOrUndefined(env.localAppData); if (localAppData) { for (const version of ["Python313", "Python312", "Python311", "Python310"]) { const candidate = path.join(localAppData, "Programs", "Python", version, "python.exe"); if (yield* fs.exists(candidate)) { return candidate; } } } } const probe = yield* spawnAndCollectOutput( ChildProcess.make("python", ["-c", "import sys;print(sys.executable)"]), ).pipe( Effect.orElseSucceed(() => ({ stdout: "", stderr: "", exitCode: 1, })), ); if (probe.exitCode !== 0) { return undefined; } const executable = probe.stdout.trim(); if (!executable || !(yield* fs.exists(executable))) { return undefined; } return executable;}); interface ResolvedBuildOptions { readonly platform: typeof BuildPlatform.Type; readonly target: string; readonly arch: typeof BuildArch.Type; readonly version: string | undefined; readonly outputDir: string; readonly skipBuild: boolean; readonly keepStage: boolean; readonly signed: boolean; readonly verbose: boolean; readonly mockUpdates: boolean; readonly mockUpdateServerPort: number | undefined;} interface StagePackageJson { readonly name: string; readonly version: string; readonly buildVersion: string; readonly t3codeCommitHash: string; readonly private: true; readonly packageManager: string; readonly description: string; readonly author: string; readonly main: string; readonly build: Record<string, unknown>; readonly dependencies: Record<string, unknown>; readonly devDependencies: { readonly electron: string; }; readonly overrides: Record<string, unknown>; readonly pnpm?: { readonly patchedDependencies?: Record<string, string>; };} export const STAGE_INSTALL_ARGS = ["install", "--prod"] as const;export const DESKTOP_ASAR_UNPACK = ["node_modules/@ff-labs/fff-bin-*/**/*"] as const; export interface MacPasskeySigningConfiguration { readonly appId: string; readonly teamId: string; readonly rpDomains: readonly string[]; readonly provisioningProfilePath: string;} export const InvalidMacPasskeyRpDomainReason = Schema.Literals([ "empty", "scheme-not-allowed", "parse-failed", "credentials-not-allowed", "port-not-allowed", "path-not-allowed", "query-not-allowed", "fragment-not-allowed", "hostname-mismatch",]);export type InvalidMacPasskeyRpDomainReason = typeof InvalidMacPasskeyRpDomainReason.Type; export class InvalidMacPasskeyRpDomainError extends Schema.TaggedErrorClass<InvalidMacPasskeyRpDomainError>()( "InvalidMacPasskeyRpDomainError", { reason: InvalidMacPasskeyRpDomainReason, inputLength: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)), cause: Schema.optionalKey(Schema.Defect()), },) { override get message(): string { return `Invalid passkey RP domain (${this.reason}).`; }} export class InvalidAppleTeamIdError extends Schema.TaggedErrorClass<InvalidAppleTeamIdError>()( "InvalidAppleTeamIdError", { teamId: Schema.String, },) { override get message(): string { return `T3CODE_APPLE_TEAM_ID '${this.teamId}' must be a 10-character Apple Developer Team ID.`; }} export class MissingMacPasskeyProvisioningProfileError extends Schema.TaggedErrorClass<MissingMacPasskeyProvisioningProfileError>()( "MissingMacPasskeyProvisioningProfileError", {},) { override get message(): string { return "T3CODE_MACOS_PROVISIONING_PROFILE must point to an Associated Domains provisioning profile."; }} export class MissingMacPasskeyDomainConfigurationError extends Schema.TaggedErrorClass<MissingMacPasskeyDomainConfigurationError>()( "MissingMacPasskeyDomainConfigurationError", {},) { override get message(): string { return "T3CODE_CLERK_PUBLISHABLE_KEY or T3CODE_CLERK_PASSKEY_RP_DOMAINS is required for signed macOS passkey builds."; }} export class InvalidMacPasskeyPublishableKeyError extends Schema.TaggedErrorClass<InvalidMacPasskeyPublishableKeyError>()( "InvalidMacPasskeyPublishableKeyError", { cause: Schema.Defect(), },) { override get message(): string { return "T3CODE_CLERK_PUBLISHABLE_KEY is invalid."; }} export class MissingMacPasskeyRpDomainError extends Schema.TaggedErrorClass<MissingMacPasskeyRpDomainError>()( "MissingMacPasskeyRpDomainError", {},) { override get message(): string { return "At least one Clerk passkey RP domain is required."; }} export const MacPasskeySigningConfigurationError = Schema.Union([ InvalidMacPasskeyRpDomainError, InvalidAppleTeamIdError, MissingMacPasskeyProvisioningProfileError, MissingMacPasskeyDomainConfigurationError, InvalidMacPasskeyPublishableKeyError, MissingMacPasskeyRpDomainError,]);export type MacPasskeySigningConfigurationError = typeof MacPasskeySigningConfigurationError.Type;export const isMacPasskeySigningConfigurationError = Schema.is(MacPasskeySigningConfigurationError); function normalizePasskeyRpDomain(value: string): string { const normalized = value.trim().toLowerCase(); const inputLength = value.length; if (normalized.length === 0) { throw new InvalidMacPasskeyRpDomainError({ reason: "empty", inputLength }); } if (/^[a-z][a-z\d+.-]*:\/\//u.test(normalized)) { throw new InvalidMacPasskeyRpDomainError({ reason: "scheme-not-allowed", inputLength, }); } let parsed: URL; try { parsed = new URL(`https://${normalized}`); } catch (cause) { throw new InvalidMacPasskeyRpDomainError({ reason: "parse-failed", inputLength, cause }); } let reason: InvalidMacPasskeyRpDomainReason | undefined; if (parsed.username.length > 0 || parsed.password.length > 0) { reason = "credentials-not-allowed"; } else if (parsed.port.length > 0) { reason = "port-not-allowed"; } else if (parsed.pathname !== "/") { reason = "path-not-allowed"; } else if (parsed.search.length > 0) { reason = "query-not-allowed"; } else if (parsed.hash.length > 0) { reason = "fragment-not-allowed"; } else if (parsed.host !== normalized) { reason = "hostname-mismatch"; } if (reason) { throw new InvalidMacPasskeyRpDomainError({ reason, inputLength }); } return parsed.hostname;} export function resolveMacPasskeySigningConfiguration( env: Readonly<Record<string, string | undefined>>,): MacPasskeySigningConfiguration { const teamId = env.T3CODE_APPLE_TEAM_ID?.trim().toUpperCase() ?? ""; if (!APPLE_TEAM_ID_PATTERN.test(teamId)) { throw new InvalidAppleTeamIdError({ teamId }); } const provisioningProfilePath = env.T3CODE_MACOS_PROVISIONING_PROFILE?.trim() ?? ""; if (provisioningProfilePath.length === 0) { throw new MissingMacPasskeyProvisioningProfileError(); } const configuredRpDomains = env.T3CODE_CLERK_PASSKEY_RP_DOMAINS?.trim(); let rpDomains: readonly string[]; if (configuredRpDomains) { rpDomains = configuredRpDomains.split(",").map(normalizePasskeyRpDomain); } else { const publishableKey = env.T3CODE_CLERK_PUBLISHABLE_KEY?.trim(); if (!publishableKey) { throw new MissingMacPasskeyDomainConfigurationError(); } let hostname: string; try { hostname = clerkFrontendApiHostnameFromPublishableKey(publishableKey); } catch (cause) { throw new InvalidMacPasskeyPublishableKeyError({ cause }); } rpDomains = [normalizePasskeyRpDomain(hostname)]; } const uniqueRpDomains = [...new Set(rpDomains)]; if (uniqueRpDomains.length === 0) { throw new MissingMacPasskeyRpDomainError(); } return { appId: DESKTOP_APP_ID, teamId, rpDomains: uniqueRpDomains, provisioningProfilePath, };} function escapeXml(value: string): string { return value .replaceAll("&", "&") .replaceAll("<", "<") .replaceAll(">", ">") .replaceAll('"', """) .replaceAll("'", "'");} export function renderMacPasskeyEntitlements(Lines 1–500 of 1518. Load more
#!/usr/bin/env node import * as NodeModule from "node:module"; import { fromYaml } from "@t3tools/shared/schemaYaml"; import { HostProcessPlatform } from "@t3tools/shared/hostProcess"; import { clerkFrontendApiHostnameFromPublishableKey } from "@t3tools/shared/relayAuth"; import { resolveSpawnCommand } from "@t3tools/shared/shell"; import rootPackageJson from "../package.json" with { type: "json" }; import desktopPackageJson from "../apps/desktop/package.json" with { type: "json" }; import serverPackageJson from "../apps/server/package.json" with { type: "json" }; import { BRAND_ASSET_PATHS } from "./lib/brand-assets.ts"; import { getDefaultBuildArch } from "./lib/build-target-arch.ts"; import { loadRepoEnv } from "./lib/public-config.ts"; import { resolveCatalogDependencies } from "./lib/resolve-catalog.ts"; import * as NodeRuntime from "@effect/platform-node/NodeRuntime"; import * as NodeServices from "@effect/platform-node/NodeServices"; import * as Config from "effect/Config"; import * as Data from "effect/Data"; import * as Effect from "effect/Effect"; import * as FileSystem from "effect/FileSystem"; import * as Layer from "effect/Layer"; import * as Logger from "effect/Logger"; import * as Option from "effect/Option"; import * as Path from "effect/Path"; import * as Schema from "effect/Schema"; import * as Stream from "effect/Stream"; import { Command, Flag } from "effect/unstable/cli"; import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process"; const LINUX_ICON_SIZES = [16, 22, 24, 32, 48, 64, 128, 256, 512] as const; const DESKTOP_APP_ID = "com.t3tools.t3code"; const APPLE_TEAM_ID_PATTERN = /^[A-Z0-9]{10}$/u; const BuildPlatform = Schema.Literals(["mac", "linux", "win"]); const BuildArch = Schema.Literals(["arm64", "x64", "universal"]); const WorkspaceConfig = Schema.Struct({ catalog: Schema.optional(Schema.Record(Schema.String, Schema.String)), overrides: Schema.optional(Schema.Record(Schema.String, Schema.String)), patchedDependencies: Schema.optional(Schema.Record(Schema.String, Schema.String)), }); type WorkspaceConfig = typeof WorkspaceConfig.Type; const StageWorkspaceConfig = Schema.Struct({ supportedArchitectures: Schema.Struct({ os: Schema.Array(Schema.String), cpu: Schema.Array(Schema.String), }), }); const RepoRoot = Effect.service(Path.Path).pipe( Effect.flatMap((path) => path.fromFileUrl(new URL("..", import.meta.url))), ); const encodeJsonString = Schema.encodeEffect(Schema.UnknownFromJsonString); const decodeWorkspaceConfig = Schema.decodeEffect(fromYaml(WorkspaceConfig)); const encodeStageWorkspaceConfig = Schema.encodeEffect(fromYaml(StageWorkspaceConfig)); const readWorkspaceConfig = Effect.fn("readWorkspaceConfig")(function* () { const fs = yield* FileSystem.FileSystem; const path = yield* Path.Path; const repoRoot = yield* RepoRoot; const workspaceYaml = yield* fs.readFileString(path.join(repoRoot, "pnpm-workspace.yaml")); return yield* decodeWorkspaceConfig(workspaceYaml); }); interface DesktopBuildIconAssets { readonly macIconPng: string; readonly linuxIconPng: string; readonly windowsIconIco: string; } interface PlatformConfig { readonly cliFlag: "--mac" | "--linux" | "--win"; readonly defaultTarget: string; readonly archChoices: ReadonlyArray<typeof BuildArch.Type>; } const PLATFORM_CONFIG: Record<typeof BuildPlatform.Type, PlatformConfig> = { mac: { cliFlag: "--mac", defaultTarget: "dmg", archChoices: ["arm64", "x64", "universal"], }, linux: { cliFlag: "--linux", defaultTarget: "AppImage", archChoices: ["x64", "arm64"], }, win: { cliFlag: "--win", defaultTarget: "nsis", archChoices: ["x64", "arm64"], }, }; interface BuildCliInput { readonly platform: Option.Option<typeof BuildPlatform.Type>; readonly target: Option.Option<string>; readonly arch: Option.Option<typeof BuildArch.Type>; readonly buildVersion: Option.Option<string>; readonly outputDir: Option.Option<string>; readonly skipBuild: Option.Option<boolean>; readonly keepStage: Option.Option<boolean>; readonly signed: Option.Option<boolean>; readonly verbose: Option.Option<boolean>; readonly mockUpdates: Option.Option<boolean>; readonly mockUpdateServerPort: Option.Option<number>; } function detectHostBuildPlatform(hostPlatform: string): typeof BuildPlatform.Type | undefined { if (hostPlatform === "darwin") return "mac"; if (hostPlatform === "linux") return "linux"; if (hostPlatform === "win32") return "win"; return undefined; } const getDefaultArch = Effect.fn("getDefaultArch")(function* (platform: typeof BuildPlatform.Type) { const config = PLATFORM_CONFIG[platform]; if (!config) { return "x64"; } return yield* getDefaultBuildArch(platform, config); }); export class BuildScriptError extends Data.TaggedError("BuildScriptError")<{ readonly message: string; readonly cause?: unknown; }> { static fromMacPasskeySigningConfiguration( cause: unknown, ): MacPasskeySigningConfigurationError | BuildScriptError { return isMacPasskeySigningConfigurationError(cause) ? cause : new BuildScriptError({ message: "Failed to resolve macOS passkey signing configuration.", cause, }); } } const collectStreamAsString = <E>(stream: Stream.Stream<Uint8Array, E>): Effect.Effect<string, E> => stream.pipe( Stream.decodeText(), Stream.runFold( () => "", (acc, chunk) => acc + chunk, ), ); const COMMAND_OUTPUT_TAIL_LENGTH = 20_000; function appendOutputTail(acc: string, chunk: string): string { const next = acc + chunk; return next.length > COMMAND_OUTPUT_TAIL_LENGTH ? next.slice(-COMMAND_OUTPUT_TAIL_LENGTH) : next; } function formatOutputSection(label: string, output: string): string | undefined { const trimmed = output.trim(); if (!trimmed) return undefined; return `${label} tail:\n${trimmed}`; } const collectCommandStream = <E>( stream: Stream.Stream<Uint8Array, E>, output: NodeJS.WriteStream, verbose: boolean, ): Effect.Effect<string, E> => stream.pipe( Stream.decodeText(), Stream.runFoldEffect( () => "", (acc, chunk) => Effect.as( verbose ? Effect.sync(() => output.write(chunk)) : Effect.void, appendOutputTail(acc, chunk), ), ), ); const spawnAndCollectOutput = Effect.fn("spawnAndCollectOutput")(function* ( command: ChildProcess.Command, ) { const spawner = yield* ChildProcessSpawner.ChildProcessSpawner; const child = yield* spawner.spawn(command); const [stdout, stderr, exitCode] = yield* Effect.all( [ collectStreamAsString(child.stdout), collectStreamAsString(child.stderr), child.exitCode.pipe(Effect.map(Number)), ], { concurrency: "unbounded" }, ); return { stdout, stderr, exitCode } as const; }); const resolveGitCommitHash = Effect.fn("resolveGitCommitHash")(function* (repoRoot: string) { const result = yield* spawnAndCollectOutput( ChildProcess.make("git", ["rev-parse", "--short=12", "HEAD"], { cwd: repoRoot, }), ).pipe( Effect.orElseSucceed(() => ({ stdout: "", stderr: "", exitCode: 1, })), ); if (result.exitCode !== 0) { return "unknown"; } const hash = result.stdout.trim(); if (!/^[0-9a-f]{7,40}$/i.test(hash)) { return "unknown"; } return hash.toLowerCase(); }); const resolvePythonForNodeGyp = Effect.fn("resolvePythonForNodeGyp")(function* () { const fs = yield* FileSystem.FileSystem; const path = yield* Path.Path; const hostPlatform = yield* HostProcessPlatform; const env = yield* Config.all({ configuredPython: Config.string("npm_config_python").pipe( Config.orElse(() => Config.string("PYTHON")), Config.option, ), localAppData: Config.string("LOCALAPPDATA").pipe(Config.option), }); const configured = Option.getOrUndefined(env.configuredPython); if (configured && (yield* fs.exists(configured))) { return configured; } if (hostPlatform === "win32") { const localAppData = Option.getOrUndefined(env.localAppData); if (localAppData) { for (const version of ["Python313", "Python312", "Python311", "Python310"]) { const candidate = path.join(localAppData, "Programs", "Python", version, "python.exe"); if (yield* fs.exists(candidate)) { return candidate; } } } } const probe = yield* spawnAndCollectOutput( ChildProcess.make("python", ["-c", "import sys;print(sys.executable)"]), ).pipe( Effect.orElseSucceed(() => ({ stdout: "", stderr: "", exitCode: 1, })), ); if (probe.exitCode !== 0) { return undefined; } const executable = probe.stdout.trim(); if (!executable || !(yield* fs.exists(executable))) { return undefined; } return executable; }); interface ResolvedBuildOptions { readonly platform: typeof BuildPlatform.Type; readonly target: string; readonly arch: typeof BuildArch.Type; readonly version: string | undefined; readonly outputDir: string; readonly skipBuild: boolean; readonly keepStage: boolean; readonly signed: boolean; readonly verbose: boolean; readonly mockUpdates: boolean; readonly mockUpdateServerPort: number | undefined; } interface StagePackageJson { readonly name: string; readonly version: string; readonly buildVersion: string; readonly t3codeCommitHash: string; readonly private: true; readonly packageManager: string; readonly description: string; readonly author: string; readonly main: string; readonly build: Record<string, unknown>; readonly dependencies: Record<string, unknown>; readonly devDependencies: { readonly electron: string; }; readonly overrides: Record<string, unknown>; readonly pnpm?: { readonly patchedDependencies?: Record<string, string>; }; } export const STAGE_INSTALL_ARGS = ["install", "--prod"] as const; export const DESKTOP_ASAR_UNPACK = ["node_modules/@ff-labs/fff-bin-*/**/*"] as const; export interface MacPasskeySigningConfiguration { readonly appId: string; readonly teamId: string; readonly rpDomains: readonly string[]; readonly provisioningProfilePath: string; } export const InvalidMacPasskeyRpDomainReason = Schema.Literals([ "empty", "scheme-not-allowed", "parse-failed", "credentials-not-allowed", "port-not-allowed", "path-not-allowed", "query-not-allowed", "fragment-not-allowed", "hostname-mismatch", ]); export type InvalidMacPasskeyRpDomainReason = typeof InvalidMacPasskeyRpDomainReason.Type; export class InvalidMacPasskeyRpDomainError extends Schema.TaggedErrorClass<InvalidMacPasskeyRpDomainError>()( "InvalidMacPasskeyRpDomainError", { reason: InvalidMacPasskeyRpDomainReason, inputLength: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)), cause: Schema.optionalKey(Schema.Defect()), }, ) { override get message(): string { return `Invalid passkey RP domain (${this.reason}).`; } } export class InvalidAppleTeamIdError extends Schema.TaggedErrorClass<InvalidAppleTeamIdError>()( "InvalidAppleTeamIdError", { teamId: Schema.String, }, ) { override get message(): string { return `T3CODE_APPLE_TEAM_ID '${this.teamId}' must be a 10-character Apple Developer Team ID.`; } } export class MissingMacPasskeyProvisioningProfileError extends Schema.TaggedErrorClass<MissingMacPasskeyProvisioningProfileError>()( "MissingMacPasskeyProvisioningProfileError", {}, ) { override get message(): string { return "T3CODE_MACOS_PROVISIONING_PROFILE must point to an Associated Domains provisioning profile."; } } export class MissingMacPasskeyDomainConfigurationError extends Schema.TaggedErrorClass<MissingMacPasskeyDomainConfigurationError>()( "MissingMacPasskeyDomainConfigurationError", {}, ) { override get message(): string { return "T3CODE_CLERK_PUBLISHABLE_KEY or T3CODE_CLERK_PASSKEY_RP_DOMAINS is required for signed macOS passkey builds."; } } export class InvalidMacPasskeyPublishableKeyError extends Schema.TaggedErrorClass<InvalidMacPasskeyPublishableKeyError>()( "InvalidMacPasskeyPublishableKeyError", { cause: Schema.Defect(), }, ) { override get message(): string { return "T3CODE_CLERK_PUBLISHABLE_KEY is invalid."; } } export class MissingMacPasskeyRpDomainError extends Schema.TaggedErrorClass<MissingMacPasskeyRpDomainError>()( "MissingMacPasskeyRpDomainError", {}, ) { override get message(): string { return "At least one Clerk passkey RP domain is required."; } } export const MacPasskeySigningConfigurationError = Schema.Union([ InvalidMacPasskeyRpDomainError, InvalidAppleTeamIdError, MissingMacPasskeyProvisioningProfileError, MissingMacPasskeyDomainConfigurationError, InvalidMacPasskeyPublishableKeyError, MissingMacPasskeyRpDomainError, ]); export type MacPasskeySigningConfigurationError = typeof MacPasskeySigningConfigurationError.Type; export const isMacPasskeySigningConfigurationError = Schema.is(MacPasskeySigningConfigurationError); function normalizePasskeyRpDomain(value: string): string { const normalized = value.trim().toLowerCase(); const inputLength = value.length; if (normalized.length === 0) { throw new InvalidMacPasskeyRpDomainError({ reason: "empty", inputLength }); } if (/^[a-z][a-z\d+.-]*:\/\//u.test(normalized)) { throw new InvalidMacPasskeyRpDomainError({ reason: "scheme-not-allowed", inputLength, }); } let parsed: URL; try { parsed = new URL(`https://${normalized}`); } catch (cause) { throw new InvalidMacPasskeyRpDomainError({ reason: "parse-failed", inputLength, cause }); } let reason: InvalidMacPasskeyRpDomainReason | undefined; if (parsed.username.length > 0 || parsed.password.length > 0) { reason = "credentials-not-allowed"; } else if (parsed.port.length > 0) { reason = "port-not-allowed"; } else if (parsed.pathname !== "/") { reason = "path-not-allowed"; } else if (parsed.search.length > 0) { reason = "query-not-allowed"; } else if (parsed.hash.length > 0) { reason = "fragment-not-allowed"; } else if (parsed.host !== normalized) { reason = "hostname-mismatch"; } if (reason) { throw new InvalidMacPasskeyRpDomainError({ reason, inputLength }); } return parsed.hostname; } export function resolveMacPasskeySigningConfiguration( env: Readonly<Record<string, string | undefined>>, ): MacPasskeySigningConfiguration { const teamId = env.T3CODE_APPLE_TEAM_ID?.trim().toUpperCase() ?? ""; if (!APPLE_TEAM_ID_PATTERN.test(teamId)) { throw new InvalidAppleTeamIdError({ teamId }); } const provisioningProfilePath = env.T3CODE_MACOS_PROVISIONING_PROFILE?.trim() ?? ""; if (provisioningProfilePath.length === 0) { throw new MissingMacPasskeyProvisioningProfileError(); } const configuredRpDomains = env.T3CODE_CLERK_PASSKEY_RP_DOMAINS?.trim(); let rpDomains: readonly string[]; if (configuredRpDomains) { rpDomains = configuredRpDomains.split(",").map(normalizePasskeyRpDomain); } else { const publishableKey = env.T3CODE_CLERK_PUBLISHABLE_KEY?.trim(); if (!publishableKey) { throw new MissingMacPasskeyDomainConfigurationError(); } let hostname: string; try { hostname = clerkFrontendApiHostnameFromPublishableKey(publishableKey); } catch (cause) { throw new InvalidMacPasskeyPublishableKeyError({ cause }); } rpDomains = [normalizePasskeyRpDomain(hostname)]; } const uniqueRpDomains = [...new Set(rpDomains)]; if (uniqueRpDomains.length === 0) { throw new MissingMacPasskeyRpDomainError(); } return { appId: DESKTOP_APP_ID, teamId, rpDomains: uniqueRpDomains, provisioningProfilePath, }; } function escapeXml(value: string): string { return value .replaceAll("&", "&") .replaceAll("<", "<") .replaceAll(">", ">") .replaceAll('"', """) .replaceAll("'", "'"); } export function renderMacPasskeyEntitlements(