@ebay-dt/bonfire-node 0.1.0-alpha.0 → 0.1.0-alpha.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.
Files changed (77) hide show
  1. package/README.md +77 -4
  2. package/dist/agent-service.d.ts +42 -0
  3. package/dist/agent-service.d.ts.map +1 -0
  4. package/dist/agent-service.js +116 -0
  5. package/dist/agent-service.js.map +1 -0
  6. package/dist/claude.d.ts +50 -0
  7. package/dist/claude.d.ts.map +1 -0
  8. package/dist/claude.js +119 -0
  9. package/dist/claude.js.map +1 -0
  10. package/dist/cursor.d.ts +30 -0
  11. package/dist/cursor.d.ts.map +1 -0
  12. package/dist/cursor.js +57 -0
  13. package/dist/cursor.js.map +1 -0
  14. package/dist/deployment-provider.d.ts +32 -0
  15. package/dist/deployment-provider.d.ts.map +1 -0
  16. package/dist/deployment-provider.js +167 -0
  17. package/dist/deployment-provider.js.map +1 -0
  18. package/dist/duplicate.d.ts +3 -2
  19. package/dist/duplicate.d.ts.map +1 -1
  20. package/dist/duplicate.js +18 -18
  21. package/dist/duplicate.js.map +1 -1
  22. package/dist/executable.d.ts +16 -0
  23. package/dist/executable.d.ts.map +1 -0
  24. package/dist/executable.js +65 -0
  25. package/dist/executable.js.map +1 -0
  26. package/dist/git-repository.d.ts.map +1 -1
  27. package/dist/git-repository.js.map +1 -1
  28. package/dist/github-cli.d.ts.map +1 -1
  29. package/dist/github-cli.js +23 -3
  30. package/dist/github-cli.js.map +1 -1
  31. package/dist/index.d.ts +7 -1
  32. package/dist/index.d.ts.map +1 -1
  33. package/dist/index.js +7 -0
  34. package/dist/index.js.map +1 -1
  35. package/dist/internal/owned-destination.d.ts +2 -2
  36. package/dist/internal/owned-destination.d.ts.map +1 -1
  37. package/dist/internal/owned-destination.js +2 -2
  38. package/dist/internal/owned-destination.js.map +1 -1
  39. package/dist/internal/prototype-templates.d.ts +3 -2
  40. package/dist/internal/prototype-templates.d.ts.map +1 -1
  41. package/dist/internal/prototype-templates.js +13 -8
  42. package/dist/internal/prototype-templates.js.map +1 -1
  43. package/dist/internal/utils.d.ts +2 -0
  44. package/dist/internal/utils.d.ts.map +1 -1
  45. package/dist/internal/utils.js +6 -0
  46. package/dist/internal/utils.js.map +1 -1
  47. package/dist/lifecycle/dirty-state.d.ts.map +1 -1
  48. package/dist/lifecycle/dirty-state.js.map +1 -1
  49. package/dist/lifecycle/local-prototype-lifecycle.d.ts +22 -10
  50. package/dist/lifecycle/local-prototype-lifecycle.d.ts.map +1 -1
  51. package/dist/lifecycle/local-prototype-lifecycle.js +255 -6
  52. package/dist/lifecycle/local-prototype-lifecycle.js.map +1 -1
  53. package/dist/lifecycle/operation-gate.d.ts.map +1 -1
  54. package/dist/lifecycle/operation-gate.js.map +1 -1
  55. package/dist/lifecycle/runtime-context.d.ts.map +1 -1
  56. package/dist/lifecycle/runtime-context.js.map +1 -1
  57. package/dist/preferences.d.ts +19 -0
  58. package/dist/preferences.d.ts.map +1 -0
  59. package/dist/preferences.js +182 -0
  60. package/dist/preferences.js.map +1 -0
  61. package/dist/prepare-prototype-files.d.ts.map +1 -1
  62. package/dist/prepare-prototype-files.js.map +1 -1
  63. package/dist/process-runner.d.ts.map +1 -1
  64. package/dist/process-runner.js.map +1 -1
  65. package/dist/prototype-catalog.d.ts.map +1 -1
  66. package/dist/prototype-catalog.js +18 -7
  67. package/dist/prototype-catalog.js.map +1 -1
  68. package/dist/prototype-paths.d.ts +2 -0
  69. package/dist/prototype-paths.d.ts.map +1 -1
  70. package/dist/prototype-paths.js.map +1 -1
  71. package/dist/scaffold.d.ts +4 -2
  72. package/dist/scaffold.d.ts.map +1 -1
  73. package/dist/scaffold.js +7 -12
  74. package/dist/scaffold.js.map +1 -1
  75. package/dist/watcher.d.ts.map +1 -1
  76. package/dist/watcher.js.map +1 -1
  77. package/package.json +3 -3
@@ -0,0 +1,32 @@
1
+ import type { DeploymentReadyState } from "@ebay-dt/bonfire-core";
2
+ /**
3
+ * The normalized result returned by a deployment provider. `url` is the
4
+ * deployment-root URL; the lifecycle service adds the active prototype route.
5
+ */
6
+ export type DeploymentProviderResult = {
7
+ url: string;
8
+ deploymentId: string;
9
+ readyState: DeploymentReadyState;
10
+ };
11
+ /** Server-side transport boundary for creating an application deployment. */
12
+ export interface DeploymentProvider {
13
+ deploy(input: {
14
+ applicationId: string;
15
+ login: string;
16
+ }): Promise<DeploymentProviderResult>;
17
+ }
18
+ export type CreateDeploymentProviderOptions = {
19
+ endpoint: string;
20
+ timeoutMs?: number;
21
+ };
22
+ export type DeploymentProviderErrorKind = "timeout" | "service-failure" | "invalid-response" | "invalid-url" | "invalid-configuration";
23
+ /**
24
+ * Safe provider failure classification. It intentionally carries no response
25
+ * body, endpoint credentials, or unbounded service diagnostics.
26
+ */
27
+ export declare class DeploymentProviderError extends Error {
28
+ readonly kind: DeploymentProviderErrorKind;
29
+ constructor(kind: DeploymentProviderErrorKind);
30
+ }
31
+ export declare function createDeploymentProvider({ endpoint: configuredEndpoint, timeoutMs: configuredTimeout, }: CreateDeploymentProviderOptions): DeploymentProvider;
32
+ //# sourceMappingURL=deployment-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deployment-provider.d.ts","sourceRoot":"","sources":["../src/deployment-provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAQlE;;;GAGG;AACH,MAAM,MAAM,wBAAwB,GAAG;IACrC,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,oBAAoB,CAAC;CAClC,CAAC;AAEF,6EAA6E;AAC7E,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,KAAK,EAAE;QACZ,aAAa,EAAE,MAAM,CAAC;QACtB,KAAK,EAAE,MAAM,CAAC;KACf,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAAC;CACvC;AAED,MAAM,MAAM,+BAA+B,GAAG;IAC5C,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,2BAA2B,GACnC,SAAS,GACT,iBAAiB,GACjB,kBAAkB,GAClB,aAAa,GACb,uBAAuB,CAAC;AAE5B;;;GAGG;AACH,qBAAa,uBAAwB,SAAQ,KAAK;IAChD,QAAQ,CAAC,IAAI,EAAE,2BAA2B,CAAC;IAE3C,YAAY,IAAI,EAAE,2BAA2B,EAI5C;CACF;AA8KD,wBAAgB,wBAAwB,CAAC,EACvC,QAAQ,EAAE,kBAAkB,EAC5B,SAAS,EAAE,iBAAiB,GAC7B,EAAE,+BAA+B,GAAG,kBAAkB,CA2CtD","sourcesContent":["import type { DeploymentReadyState } from \"@ebay-dt/bonfire-core\";\nimport { isDeploymentReadyState } from \"@ebay-dt/bonfire-core\";\nimport { isRecord } from \"./internal/utils.js\";\n\nconst DEFAULT_TIMEOUT_MS = 120_000;\nconst MAX_RESPONSE_STRING_LENGTH = 2_000;\nconst MAX_RESPONSE_URL_LENGTH = 8_192;\n\n/**\n * The normalized result returned by a deployment provider. `url` is the\n * deployment-root URL; the lifecycle service adds the active prototype route.\n */\nexport type DeploymentProviderResult = {\n url: string;\n deploymentId: string;\n readyState: DeploymentReadyState;\n};\n\n/** Server-side transport boundary for creating an application deployment. */\nexport interface DeploymentProvider {\n deploy(input: {\n applicationId: string;\n login: string;\n }): Promise<DeploymentProviderResult>;\n}\n\nexport type CreateDeploymentProviderOptions = {\n endpoint: string;\n timeoutMs?: number;\n};\n\nexport type DeploymentProviderErrorKind =\n | \"timeout\"\n | \"service-failure\"\n | \"invalid-response\"\n | \"invalid-url\"\n | \"invalid-configuration\";\n\n/**\n * Safe provider failure classification. It intentionally carries no response\n * body, endpoint credentials, or unbounded service diagnostics.\n */\nexport class DeploymentProviderError extends Error {\n readonly kind: DeploymentProviderErrorKind;\n\n constructor(kind: DeploymentProviderErrorKind) {\n super(\"Deployment provider request failed\");\n this.name = \"DeploymentProviderError\";\n this.kind = kind;\n }\n}\n\n/**\n * Internal DT deployment success wire shape. The service diagnostics are\n * validated at the transport boundary but are not exposed as client data.\n */\ntype DeploymentServiceSuccessResponse = {\n repository: string;\n ref: string;\n commitSha: string;\n sourceFileCount: number;\n project: string;\n deployed: true;\n deploymentId: string;\n url: string;\n readyState: DeploymentReadyState;\n};\n\n/** Internal DT deployment failure wire shape. */\ntype DeploymentServiceFailureResponse = {\n repository: string;\n ref?: string;\n commitSha?: string;\n project?: string;\n stage?: string;\n deployed: false;\n statusCode: number;\n details: string;\n};\n\ntype DeploymentServiceResponse =\n DeploymentServiceSuccessResponse | DeploymentServiceFailureResponse;\n\nfunction isBoundedString(\n value: unknown,\n options: { allowEmpty?: boolean; maxLength?: number } = {},\n): value is string {\n if (typeof value !== \"string\") return false;\n if (!options.allowEmpty && value.length === 0) return false;\n return value.length <= (options.maxLength ?? MAX_RESPONSE_STRING_LENGTH);\n}\n\nfunction validateEndpoint(value: unknown): string {\n if (\n typeof value !== \"string\" ||\n value.length === 0 ||\n value.trim() !== value\n ) {\n throw new DeploymentProviderError(\"invalid-configuration\");\n }\n\n let endpoint: URL;\n try {\n endpoint = new URL(value);\n } catch {\n throw new DeploymentProviderError(\"invalid-configuration\");\n }\n\n if (\n (endpoint.protocol !== \"http:\" && endpoint.protocol !== \"https:\") ||\n endpoint.username !== \"\" ||\n endpoint.password !== \"\" ||\n endpoint.search !== \"\" ||\n endpoint.hash !== \"\"\n ) {\n throw new DeploymentProviderError(\"invalid-configuration\");\n }\n\n return value;\n}\n\nfunction validateTimeout(value: unknown): number {\n if (\n value === undefined ||\n (typeof value === \"number\" &&\n Number.isFinite(value) &&\n Number.isInteger(value) &&\n value > 0)\n ) {\n return value ?? DEFAULT_TIMEOUT_MS;\n }\n\n throw new DeploymentProviderError(\"invalid-configuration\");\n}\n\nfunction parseDeploymentUrl(value: unknown): string | null {\n if (!isBoundedString(value, { maxLength: MAX_RESPONSE_URL_LENGTH })) {\n return null;\n }\n\n let url: URL;\n try {\n url = new URL(value);\n } catch {\n return null;\n }\n\n if (url.protocol !== \"https:\" || url.username !== \"\" || url.password !== \"\") {\n return null;\n }\n\n return url.toString().replace(/\\/$/, \"\");\n}\n\nfunction isDeploymentServiceSuccessResponse(\n value: unknown,\n): value is DeploymentServiceSuccessResponse {\n if (!isRecord(value)) return false;\n\n return (\n isBoundedString(value.repository) &&\n isBoundedString(value.ref) &&\n isBoundedString(value.commitSha) &&\n Number.isInteger(value.sourceFileCount) &&\n Number(value.sourceFileCount) >= 0 &&\n isBoundedString(value.project) &&\n value.deployed === true &&\n isBoundedString(value.deploymentId) &&\n isBoundedString(value.url, { maxLength: MAX_RESPONSE_URL_LENGTH }) &&\n isDeploymentReadyState(value.readyState)\n );\n}\n\nfunction isDeploymentServiceFailureResponse(\n value: unknown,\n): value is DeploymentServiceFailureResponse {\n if (!isRecord(value)) return false;\n\n const optionalStringFields = [\"ref\", \"commitSha\", \"project\", \"stage\"];\n return (\n isBoundedString(value.repository) &&\n value.deployed === false &&\n Number.isInteger(value.statusCode) &&\n Number(value.statusCode) >= 0 &&\n isBoundedString(value.details) &&\n optionalStringFields.every(\n (field) => !Object.hasOwn(value, field) || isBoundedString(value[field]),\n )\n );\n}\n\nasync function readResponse(response: Response): Promise<unknown> {\n try {\n return await response.json();\n } catch {\n throw new DeploymentProviderError(\"invalid-response\");\n }\n}\n\nfunction parseSuccessResponse(value: unknown): DeploymentProviderResult {\n if (!isDeploymentServiceSuccessResponse(value)) {\n throw new DeploymentProviderError(\"invalid-response\");\n }\n\n const url = parseDeploymentUrl(value.url);\n if (url === null) {\n throw new DeploymentProviderError(\"invalid-url\");\n }\n\n return {\n url,\n deploymentId: value.deploymentId,\n readyState: value.readyState,\n };\n}\n\nfunction parseFailureResponse(value: unknown): never {\n if (!isDeploymentServiceFailureResponse(value)) {\n throw new DeploymentProviderError(\"invalid-response\");\n }\n\n throw new DeploymentProviderError(\"service-failure\");\n}\n\nexport function createDeploymentProvider({\n endpoint: configuredEndpoint,\n timeoutMs: configuredTimeout,\n}: CreateDeploymentProviderOptions): DeploymentProvider {\n const endpoint = validateEndpoint(configuredEndpoint);\n const timeoutMs = validateTimeout(configuredTimeout);\n const fetchImplementation = globalThis.fetch;\n\n if (typeof fetchImplementation !== \"function\") {\n throw new DeploymentProviderError(\"invalid-configuration\");\n }\n\n return {\n async deploy(input) {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), timeoutMs);\n\n let response: Response;\n try {\n response = await fetchImplementation(endpoint, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n applicationId: input.applicationId,\n login: input.login,\n }),\n cache: \"no-store\",\n signal: controller.signal,\n });\n } catch {\n if (controller.signal.aborted) {\n throw new DeploymentProviderError(\"timeout\");\n }\n throw new DeploymentProviderError(\"service-failure\");\n } finally {\n clearTimeout(timeout);\n }\n\n const payload = await readResponse(response);\n if (response.status === 201) {\n return parseSuccessResponse(payload);\n }\n\n return parseFailureResponse(payload);\n },\n };\n}\n"]}
@@ -0,0 +1,167 @@
1
+ import { isDeploymentReadyState } from "@ebay-dt/bonfire-core";
2
+ import { isRecord } from "./internal/utils.js";
3
+ const DEFAULT_TIMEOUT_MS = 120_000;
4
+ const MAX_RESPONSE_STRING_LENGTH = 2_000;
5
+ const MAX_RESPONSE_URL_LENGTH = 8_192;
6
+ /**
7
+ * Safe provider failure classification. It intentionally carries no response
8
+ * body, endpoint credentials, or unbounded service diagnostics.
9
+ */
10
+ export class DeploymentProviderError extends Error {
11
+ kind;
12
+ constructor(kind) {
13
+ super("Deployment provider request failed");
14
+ this.name = "DeploymentProviderError";
15
+ this.kind = kind;
16
+ }
17
+ }
18
+ function isBoundedString(value, options = {}) {
19
+ if (typeof value !== "string")
20
+ return false;
21
+ if (!options.allowEmpty && value.length === 0)
22
+ return false;
23
+ return value.length <= (options.maxLength ?? MAX_RESPONSE_STRING_LENGTH);
24
+ }
25
+ function validateEndpoint(value) {
26
+ if (typeof value !== "string" ||
27
+ value.length === 0 ||
28
+ value.trim() !== value) {
29
+ throw new DeploymentProviderError("invalid-configuration");
30
+ }
31
+ let endpoint;
32
+ try {
33
+ endpoint = new URL(value);
34
+ }
35
+ catch {
36
+ throw new DeploymentProviderError("invalid-configuration");
37
+ }
38
+ if ((endpoint.protocol !== "http:" && endpoint.protocol !== "https:") ||
39
+ endpoint.username !== "" ||
40
+ endpoint.password !== "" ||
41
+ endpoint.search !== "" ||
42
+ endpoint.hash !== "") {
43
+ throw new DeploymentProviderError("invalid-configuration");
44
+ }
45
+ return value;
46
+ }
47
+ function validateTimeout(value) {
48
+ if (value === undefined ||
49
+ (typeof value === "number" &&
50
+ Number.isFinite(value) &&
51
+ Number.isInteger(value) &&
52
+ value > 0)) {
53
+ return value ?? DEFAULT_TIMEOUT_MS;
54
+ }
55
+ throw new DeploymentProviderError("invalid-configuration");
56
+ }
57
+ function parseDeploymentUrl(value) {
58
+ if (!isBoundedString(value, { maxLength: MAX_RESPONSE_URL_LENGTH })) {
59
+ return null;
60
+ }
61
+ let url;
62
+ try {
63
+ url = new URL(value);
64
+ }
65
+ catch {
66
+ return null;
67
+ }
68
+ if (url.protocol !== "https:" || url.username !== "" || url.password !== "") {
69
+ return null;
70
+ }
71
+ return url.toString().replace(/\/$/, "");
72
+ }
73
+ function isDeploymentServiceSuccessResponse(value) {
74
+ if (!isRecord(value))
75
+ return false;
76
+ return (isBoundedString(value.repository) &&
77
+ isBoundedString(value.ref) &&
78
+ isBoundedString(value.commitSha) &&
79
+ Number.isInteger(value.sourceFileCount) &&
80
+ Number(value.sourceFileCount) >= 0 &&
81
+ isBoundedString(value.project) &&
82
+ value.deployed === true &&
83
+ isBoundedString(value.deploymentId) &&
84
+ isBoundedString(value.url, { maxLength: MAX_RESPONSE_URL_LENGTH }) &&
85
+ isDeploymentReadyState(value.readyState));
86
+ }
87
+ function isDeploymentServiceFailureResponse(value) {
88
+ if (!isRecord(value))
89
+ return false;
90
+ const optionalStringFields = ["ref", "commitSha", "project", "stage"];
91
+ return (isBoundedString(value.repository) &&
92
+ value.deployed === false &&
93
+ Number.isInteger(value.statusCode) &&
94
+ Number(value.statusCode) >= 0 &&
95
+ isBoundedString(value.details) &&
96
+ optionalStringFields.every((field) => !Object.hasOwn(value, field) || isBoundedString(value[field])));
97
+ }
98
+ async function readResponse(response) {
99
+ try {
100
+ return await response.json();
101
+ }
102
+ catch {
103
+ throw new DeploymentProviderError("invalid-response");
104
+ }
105
+ }
106
+ function parseSuccessResponse(value) {
107
+ if (!isDeploymentServiceSuccessResponse(value)) {
108
+ throw new DeploymentProviderError("invalid-response");
109
+ }
110
+ const url = parseDeploymentUrl(value.url);
111
+ if (url === null) {
112
+ throw new DeploymentProviderError("invalid-url");
113
+ }
114
+ return {
115
+ url,
116
+ deploymentId: value.deploymentId,
117
+ readyState: value.readyState,
118
+ };
119
+ }
120
+ function parseFailureResponse(value) {
121
+ if (!isDeploymentServiceFailureResponse(value)) {
122
+ throw new DeploymentProviderError("invalid-response");
123
+ }
124
+ throw new DeploymentProviderError("service-failure");
125
+ }
126
+ export function createDeploymentProvider({ endpoint: configuredEndpoint, timeoutMs: configuredTimeout, }) {
127
+ const endpoint = validateEndpoint(configuredEndpoint);
128
+ const timeoutMs = validateTimeout(configuredTimeout);
129
+ const fetchImplementation = globalThis.fetch;
130
+ if (typeof fetchImplementation !== "function") {
131
+ throw new DeploymentProviderError("invalid-configuration");
132
+ }
133
+ return {
134
+ async deploy(input) {
135
+ const controller = new AbortController();
136
+ const timeout = setTimeout(() => controller.abort(), timeoutMs);
137
+ let response;
138
+ try {
139
+ response = await fetchImplementation(endpoint, {
140
+ method: "POST",
141
+ headers: { "Content-Type": "application/json" },
142
+ body: JSON.stringify({
143
+ applicationId: input.applicationId,
144
+ login: input.login,
145
+ }),
146
+ cache: "no-store",
147
+ signal: controller.signal,
148
+ });
149
+ }
150
+ catch {
151
+ if (controller.signal.aborted) {
152
+ throw new DeploymentProviderError("timeout");
153
+ }
154
+ throw new DeploymentProviderError("service-failure");
155
+ }
156
+ finally {
157
+ clearTimeout(timeout);
158
+ }
159
+ const payload = await readResponse(response);
160
+ if (response.status === 201) {
161
+ return parseSuccessResponse(payload);
162
+ }
163
+ return parseFailureResponse(payload);
164
+ },
165
+ };
166
+ }
167
+ //# sourceMappingURL=deployment-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deployment-provider.js","sourceRoot":"","sources":["../src/deployment-provider.ts"],"names":[],"mappings":"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","sourcesContent":["import type { DeploymentReadyState } from \"@ebay-dt/bonfire-core\";\nimport { isDeploymentReadyState } from \"@ebay-dt/bonfire-core\";\nimport { isRecord } from \"./internal/utils.js\";\n\nconst DEFAULT_TIMEOUT_MS = 120_000;\nconst MAX_RESPONSE_STRING_LENGTH = 2_000;\nconst MAX_RESPONSE_URL_LENGTH = 8_192;\n\n/**\n * The normalized result returned by a deployment provider. `url` is the\n * deployment-root URL; the lifecycle service adds the active prototype route.\n */\nexport type DeploymentProviderResult = {\n url: string;\n deploymentId: string;\n readyState: DeploymentReadyState;\n};\n\n/** Server-side transport boundary for creating an application deployment. */\nexport interface DeploymentProvider {\n deploy(input: {\n applicationId: string;\n login: string;\n }): Promise<DeploymentProviderResult>;\n}\n\nexport type CreateDeploymentProviderOptions = {\n endpoint: string;\n timeoutMs?: number;\n};\n\nexport type DeploymentProviderErrorKind =\n | \"timeout\"\n | \"service-failure\"\n | \"invalid-response\"\n | \"invalid-url\"\n | \"invalid-configuration\";\n\n/**\n * Safe provider failure classification. It intentionally carries no response\n * body, endpoint credentials, or unbounded service diagnostics.\n */\nexport class DeploymentProviderError extends Error {\n readonly kind: DeploymentProviderErrorKind;\n\n constructor(kind: DeploymentProviderErrorKind) {\n super(\"Deployment provider request failed\");\n this.name = \"DeploymentProviderError\";\n this.kind = kind;\n }\n}\n\n/**\n * Internal DT deployment success wire shape. The service diagnostics are\n * validated at the transport boundary but are not exposed as client data.\n */\ntype DeploymentServiceSuccessResponse = {\n repository: string;\n ref: string;\n commitSha: string;\n sourceFileCount: number;\n project: string;\n deployed: true;\n deploymentId: string;\n url: string;\n readyState: DeploymentReadyState;\n};\n\n/** Internal DT deployment failure wire shape. */\ntype DeploymentServiceFailureResponse = {\n repository: string;\n ref?: string;\n commitSha?: string;\n project?: string;\n stage?: string;\n deployed: false;\n statusCode: number;\n details: string;\n};\n\ntype DeploymentServiceResponse =\n DeploymentServiceSuccessResponse | DeploymentServiceFailureResponse;\n\nfunction isBoundedString(\n value: unknown,\n options: { allowEmpty?: boolean; maxLength?: number } = {},\n): value is string {\n if (typeof value !== \"string\") return false;\n if (!options.allowEmpty && value.length === 0) return false;\n return value.length <= (options.maxLength ?? MAX_RESPONSE_STRING_LENGTH);\n}\n\nfunction validateEndpoint(value: unknown): string {\n if (\n typeof value !== \"string\" ||\n value.length === 0 ||\n value.trim() !== value\n ) {\n throw new DeploymentProviderError(\"invalid-configuration\");\n }\n\n let endpoint: URL;\n try {\n endpoint = new URL(value);\n } catch {\n throw new DeploymentProviderError(\"invalid-configuration\");\n }\n\n if (\n (endpoint.protocol !== \"http:\" && endpoint.protocol !== \"https:\") ||\n endpoint.username !== \"\" ||\n endpoint.password !== \"\" ||\n endpoint.search !== \"\" ||\n endpoint.hash !== \"\"\n ) {\n throw new DeploymentProviderError(\"invalid-configuration\");\n }\n\n return value;\n}\n\nfunction validateTimeout(value: unknown): number {\n if (\n value === undefined ||\n (typeof value === \"number\" &&\n Number.isFinite(value) &&\n Number.isInteger(value) &&\n value > 0)\n ) {\n return value ?? DEFAULT_TIMEOUT_MS;\n }\n\n throw new DeploymentProviderError(\"invalid-configuration\");\n}\n\nfunction parseDeploymentUrl(value: unknown): string | null {\n if (!isBoundedString(value, { maxLength: MAX_RESPONSE_URL_LENGTH })) {\n return null;\n }\n\n let url: URL;\n try {\n url = new URL(value);\n } catch {\n return null;\n }\n\n if (url.protocol !== \"https:\" || url.username !== \"\" || url.password !== \"\") {\n return null;\n }\n\n return url.toString().replace(/\\/$/, \"\");\n}\n\nfunction isDeploymentServiceSuccessResponse(\n value: unknown,\n): value is DeploymentServiceSuccessResponse {\n if (!isRecord(value)) return false;\n\n return (\n isBoundedString(value.repository) &&\n isBoundedString(value.ref) &&\n isBoundedString(value.commitSha) &&\n Number.isInteger(value.sourceFileCount) &&\n Number(value.sourceFileCount) >= 0 &&\n isBoundedString(value.project) &&\n value.deployed === true &&\n isBoundedString(value.deploymentId) &&\n isBoundedString(value.url, { maxLength: MAX_RESPONSE_URL_LENGTH }) &&\n isDeploymentReadyState(value.readyState)\n );\n}\n\nfunction isDeploymentServiceFailureResponse(\n value: unknown,\n): value is DeploymentServiceFailureResponse {\n if (!isRecord(value)) return false;\n\n const optionalStringFields = [\"ref\", \"commitSha\", \"project\", \"stage\"];\n return (\n isBoundedString(value.repository) &&\n value.deployed === false &&\n Number.isInteger(value.statusCode) &&\n Number(value.statusCode) >= 0 &&\n isBoundedString(value.details) &&\n optionalStringFields.every(\n (field) => !Object.hasOwn(value, field) || isBoundedString(value[field]),\n )\n );\n}\n\nasync function readResponse(response: Response): Promise<unknown> {\n try {\n return await response.json();\n } catch {\n throw new DeploymentProviderError(\"invalid-response\");\n }\n}\n\nfunction parseSuccessResponse(value: unknown): DeploymentProviderResult {\n if (!isDeploymentServiceSuccessResponse(value)) {\n throw new DeploymentProviderError(\"invalid-response\");\n }\n\n const url = parseDeploymentUrl(value.url);\n if (url === null) {\n throw new DeploymentProviderError(\"invalid-url\");\n }\n\n return {\n url,\n deploymentId: value.deploymentId,\n readyState: value.readyState,\n };\n}\n\nfunction parseFailureResponse(value: unknown): never {\n if (!isDeploymentServiceFailureResponse(value)) {\n throw new DeploymentProviderError(\"invalid-response\");\n }\n\n throw new DeploymentProviderError(\"service-failure\");\n}\n\nexport function createDeploymentProvider({\n endpoint: configuredEndpoint,\n timeoutMs: configuredTimeout,\n}: CreateDeploymentProviderOptions): DeploymentProvider {\n const endpoint = validateEndpoint(configuredEndpoint);\n const timeoutMs = validateTimeout(configuredTimeout);\n const fetchImplementation = globalThis.fetch;\n\n if (typeof fetchImplementation !== \"function\") {\n throw new DeploymentProviderError(\"invalid-configuration\");\n }\n\n return {\n async deploy(input) {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), timeoutMs);\n\n let response: Response;\n try {\n response = await fetchImplementation(endpoint, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n applicationId: input.applicationId,\n login: input.login,\n }),\n cache: \"no-store\",\n signal: controller.signal,\n });\n } catch {\n if (controller.signal.aborted) {\n throw new DeploymentProviderError(\"timeout\");\n }\n throw new DeploymentProviderError(\"service-failure\");\n } finally {\n clearTimeout(timeout);\n }\n\n const payload = await readResponse(response);\n if (response.status === 201) {\n return parseSuccessResponse(payload);\n }\n\n return parseFailureResponse(payload);\n },\n };\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { type PrototypeRef } from "@ebay-dt/bonfire-core";
1
+ import { type PrototypeRef, type ThemeRegistry } from "@ebay-dt/bonfire-core";
2
2
  import { type OwnedDestinationResult } from "./internal/owned-destination.js";
3
3
  import type { ResolvedPrototypeCatalogPaths } from "./prototype-paths.js";
4
4
  type SafeWriteFile = (path: string, content: Uint8Array | string, options: {
@@ -11,6 +11,7 @@ export type DuplicatePrototypeOptions = {
11
11
  title: string;
12
12
  description: string | null;
13
13
  authorName: string | null;
14
+ themeRegistry?: ThemeRegistry;
14
15
  clock?: () => Date;
15
16
  writeFile?: SafeWriteFile;
16
17
  };
@@ -19,6 +20,6 @@ export declare class PrototypeDuplicateError extends Error {
19
20
  readonly kind: PrototypeDuplicateErrorKind;
20
21
  constructor(kind: PrototypeDuplicateErrorKind);
21
22
  }
22
- export declare function duplicatePrototype({ paths, source, destination: destinationRef, title, description, authorName, clock, writeFile, }: DuplicatePrototypeOptions): Promise<OwnedDestinationResult>;
23
+ export declare function duplicatePrototype({ paths, source, destination: destinationRef, title, description, authorName, themeRegistry, clock, writeFile, }: DuplicatePrototypeOptions): Promise<OwnedDestinationResult>;
23
24
  export {};
24
25
  //# sourceMappingURL=duplicate.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"duplicate.d.ts","sourceRoot":"","sources":["../src/duplicate.ts"],"names":[],"mappings":"AAYA,OAAO,EAIL,KAAK,YAAY,EAClB,MAAM,uBAAuB,CAAC;AAO/B,OAAO,EAEL,KAAK,sBAAsB,EAC5B,MAAM,iCAAiC,CAAC;AACzC,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,sBAAsB,CAAC;AAK1E,KAAK,aAAa,GAAG,CACnB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,UAAU,GAAG,MAAM,EAC5B,OAAO,EAAE;IAAE,IAAI,EAAE,IAAI,CAAA;CAAE,KACpB,OAAO,CAAC,IAAI,CAAC,CAAC;AAEnB,MAAM,MAAM,yBAAyB,GAAG;IACtC,KAAK,EAAE,IAAI,CACT,6BAA6B,EAC7B,gBAAgB,GAAG,eAAe,CACnC,CAAC;IACF,MAAM,EAAE,YAAY,CAAC;IACrB,WAAW,EAAE,YAAY,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,KAAK,CAAC,EAAE,MAAM,IAAI,CAAC;IACnB,SAAS,CAAC,EAAE,aAAa,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,2BAA2B,GACrC,kBAAkB,GAAG,gBAAgB,GAAG,WAAW,GAAG,YAAY,CAAC;AAErE,qBAAa,uBAAwB,SAAQ,KAAK;IAChD,QAAQ,CAAC,IAAI,EAAE,2BAA2B,CAAC;IAE3C,YAAY,IAAI,EAAE,2BAA2B,EAI5C;CACF;AAiSD,wBAAsB,kBAAkB,CAAC,EACvC,KAAK,EACL,MAAM,EACN,WAAW,EAAE,cAAc,EAC3B,KAAK,EACL,WAAW,EACX,UAAU,EACV,KAAwB,EACxB,SAA0B,GAC3B,EAAE,yBAAyB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAuH7D"}
1
+ {"version":3,"file":"duplicate.d.ts","sourceRoot":"","sources":["../src/duplicate.ts"],"names":[],"mappings":"AAYA,OAAO,EAIL,KAAK,YAAY,EACjB,KAAK,aAAa,EACnB,MAAM,uBAAuB,CAAC;AAO/B,OAAO,EAEL,KAAK,sBAAsB,EAC5B,MAAM,iCAAiC,CAAC;AACzC,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,sBAAsB,CAAC;AAM1E,KAAK,aAAa,GAAG,CACnB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,UAAU,GAAG,MAAM,EAC5B,OAAO,EAAE;IAAE,IAAI,EAAE,IAAI,CAAA;CAAE,KACpB,OAAO,CAAC,IAAI,CAAC,CAAC;AAEnB,MAAM,MAAM,yBAAyB,GAAG;IACtC,KAAK,EAAE,IAAI,CACT,6BAA6B,EAC7B,gBAAgB,GAAG,eAAe,CACnC,CAAC;IACF,MAAM,EAAE,YAAY,CAAC;IACrB,WAAW,EAAE,YAAY,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,KAAK,CAAC,EAAE,MAAM,IAAI,CAAC;IACnB,SAAS,CAAC,EAAE,aAAa,CAAC;CAC3B,CAAC;AAEF,MAAM,MAAM,2BAA2B,GACrC,kBAAkB,GAAG,gBAAgB,GAAG,WAAW,GAAG,YAAY,CAAC;AAErE,qBAAa,uBAAwB,SAAQ,KAAK;IAChD,QAAQ,CAAC,IAAI,EAAE,2BAA2B,CAAC;IAE3C,YAAY,IAAI,EAAE,2BAA2B,EAI5C;CACF;AAkSD,wBAAsB,kBAAkB,CAAC,EACvC,KAAK,EACL,MAAM,EACN,WAAW,EAAE,cAAc,EAC3B,KAAK,EACL,WAAW,EACX,UAAU,EACV,aAAa,EACb,KAAwB,EACxB,SAA0B,GAC3B,EAAE,yBAAyB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CA0H7D","sourcesContent":["import { constants } from \"node:fs\";\nimport {\n lstat,\n mkdir,\n open,\n readdir,\n rm,\n rmdir,\n writeFile as writeFileAsync,\n} from \"node:fs/promises\";\nimport { dirname, join, relative } from \"node:path\";\nimport type { Dirent } from \"node:fs\";\nimport {\n definePrototypeRef,\n parsePrototypeMetadata,\n type PrototypeMetadata,\n type PrototypeRef,\n type ThemeRegistry,\n} from \"@ebay-dt/bonfire-core\";\nimport {\n buildCssModulesDeclaration,\n buildMetadataJson,\n buildTsConfig,\n COPYABLE_IMPLEMENTATION_FILES,\n} from \"./internal/prototype-templates.js\";\nimport {\n captureOwnedDestination,\n type OwnedDestinationResult,\n} from \"./internal/owned-destination.js\";\nimport type { ResolvedPrototypeCatalogPaths } from \"./prototype-paths.js\";\nimport { isFileNotFound } from \"./internal/utils.js\";\n\nconst FILE_OPEN_FLAGS = constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0);\nconst BLOCKED_COMPONENT_NAMES = new Set([\".next\", \"node_modules\"]);\n\ntype SafeWriteFile = (\n path: string,\n content: Uint8Array | string,\n options: { flag: \"wx\" },\n) => Promise<void>;\n\nexport type DuplicatePrototypeOptions = {\n paths: Pick<\n ResolvedPrototypeCatalogPaths,\n \"repositoryRoot\" | \"prototypeRoot\"\n >;\n source: PrototypeRef;\n destination: PrototypeRef;\n title: string;\n description: string | null;\n authorName: string | null;\n themeRegistry?: ThemeRegistry;\n clock?: () => Date;\n writeFile?: SafeWriteFile;\n};\n\nexport type PrototypeDuplicateErrorKind =\n \"source-not-found\" | \"invalid-source\" | \"collision\" | \"filesystem\";\n\nexport class PrototypeDuplicateError extends Error {\n readonly kind: PrototypeDuplicateErrorKind;\n\n constructor(kind: PrototypeDuplicateErrorKind) {\n super(`Prototype duplication failed: ${kind}`);\n this.name = \"PrototypeDuplicateError\";\n this.kind = kind;\n }\n}\n\ntype OwnedPath = {\n path: string;\n device: number;\n inode: number;\n};\n\nfunction sourcePathFor(root: string, ref: PrototypeRef) {\n return join(root, ref.login, ref.slug);\n}\n\nasync function ownedPath(path: string): Promise<OwnedPath> {\n const stats = await lstat(path);\n return { path, device: stats.dev, inode: stats.ino };\n}\n\nasync function assertDirectory(\n path: string,\n kind: \"source-not-found\" | \"invalid-source\" | \"filesystem\",\n) {\n try {\n const stats = await lstat(path);\n if (stats.isSymbolicLink() || !stats.isDirectory()) {\n throw new PrototypeDuplicateError(kind);\n }\n } catch (error) {\n if (error instanceof PrototypeDuplicateError) throw error;\n if (isFileNotFound(error)) throw new PrototypeDuplicateError(kind);\n throw new PrototypeDuplicateError(\"filesystem\");\n }\n}\n\nasync function readNoFollow(\n path: string,\n kind: \"invalid-source\" | \"filesystem\",\n) {\n try {\n const stats = await lstat(path);\n if (stats.isSymbolicLink() || !stats.isFile()) {\n throw new PrototypeDuplicateError(kind);\n }\n const file = await open(path, FILE_OPEN_FLAGS);\n try {\n return await file.readFile();\n } finally {\n await file.close();\n }\n } catch (error) {\n if (error instanceof PrototypeDuplicateError) throw error;\n if (isFileNotFound(error)) return null;\n throw new PrototypeDuplicateError(kind);\n }\n}\n\nasync function readRequiredSourceFile(path: string) {\n const content = await readNoFollow(path, \"invalid-source\");\n if (content === null) {\n throw new PrototypeDuplicateError(\"invalid-source\");\n }\n return content;\n}\n\nasync function listComponentFiles(\n root: string,\n current: string,\n): Promise<string[]> {\n let entries: Dirent[];\n try {\n entries = await readdir(current, { withFileTypes: true });\n } catch {\n throw new PrototypeDuplicateError(\"invalid-source\");\n }\n\n const files: string[] = [];\n for (const entry of entries.sort((left, right) =>\n left.name.localeCompare(right.name),\n )) {\n const path = join(current, entry.name);\n let stats;\n try {\n stats = await lstat(path);\n } catch {\n throw new PrototypeDuplicateError(\"invalid-source\");\n }\n if (stats.isSymbolicLink()) {\n throw new PrototypeDuplicateError(\"invalid-source\");\n }\n if (\n entry.name === \".gitkeep\" ||\n BLOCKED_COMPONENT_NAMES.has(entry.name) ||\n entry.name.startsWith(\".env\")\n ) {\n continue;\n }\n if (stats.isDirectory()) {\n files.push(...(await listComponentFiles(root, path)));\n continue;\n }\n if (!stats.isFile()) {\n throw new PrototypeDuplicateError(\"invalid-source\");\n }\n files.push(relative(root, path));\n }\n return files;\n}\n\nasync function inspectSource(\n sourcePath: string,\n themeRegistry?: ThemeRegistry,\n) {\n await assertDirectory(sourcePath, \"source-not-found\");\n\n try {\n await lstat(join(sourcePath, \"page.module.css\"));\n throw new PrototypeDuplicateError(\"invalid-source\");\n } catch (error) {\n if (error instanceof PrototypeDuplicateError) throw error;\n if (!isFileNotFound(error)) {\n throw new PrototypeDuplicateError(\"invalid-source\");\n }\n }\n\n const metadataBytes = await readRequiredSourceFile(\n join(sourcePath, \"metadata.json\"),\n );\n let metadata: PrototypeMetadata;\n try {\n metadata = parsePrototypeMetadata(\n JSON.parse(metadataBytes.toString(\"utf8\")),\n { themeRegistry },\n );\n } catch {\n throw new PrototypeDuplicateError(\"invalid-source\");\n }\n\n const implementationFiles = new Map<string, Uint8Array>();\n for (const name of COPYABLE_IMPLEMENTATION_FILES) {\n implementationFiles.set(\n name,\n await readRequiredSourceFile(join(sourcePath, name)),\n );\n }\n\n const componentsPath = join(sourcePath, \"components\");\n let componentFiles: string[] = [];\n try {\n const stats = await lstat(componentsPath);\n if (stats.isSymbolicLink() || !stats.isDirectory()) {\n throw new PrototypeDuplicateError(\"invalid-source\");\n }\n componentFiles = await listComponentFiles(componentsPath, componentsPath);\n } catch (error) {\n if (error instanceof PrototypeDuplicateError) throw error;\n if (!isFileNotFound(error)) {\n throw new PrototypeDuplicateError(\"invalid-source\");\n }\n }\n\n return { metadata, implementationFiles, componentFiles };\n}\n\nasync function reserveDestination(\n path: string,\n paths: Pick<\n ResolvedPrototypeCatalogPaths,\n \"repositoryRoot\" | \"prototypeRoot\"\n >,\n) {\n try {\n await mkdir(path);\n } catch (error) {\n if (\n error !== null &&\n typeof error === \"object\" &&\n \"code\" in error &&\n error.code === \"EEXIST\"\n ) {\n throw new PrototypeDuplicateError(\"collision\");\n }\n throw new PrototypeDuplicateError(\"filesystem\");\n }\n try {\n return await captureOwnedDestination({\n path,\n repositoryRoot: paths.repositoryRoot,\n prototypeRoot: paths.prototypeRoot,\n });\n } catch {\n // The newly created path is retained because ownership was not proven.\n throw new PrototypeDuplicateError(\"filesystem\");\n }\n}\n\nasync function ensureDirectory(path: string) {\n try {\n await mkdir(path, { recursive: true });\n await assertDirectory(path, \"filesystem\");\n } catch (error) {\n if (error instanceof PrototypeDuplicateError) throw error;\n throw new PrototypeDuplicateError(\"filesystem\");\n }\n}\n\nasync function createDirectory(path: string) {\n try {\n await mkdir(path);\n await assertDirectory(path, \"filesystem\");\n return await ownedPath(path);\n } catch (error) {\n if (error instanceof PrototypeDuplicateError) throw error;\n throw new PrototypeDuplicateError(\"filesystem\");\n }\n}\n\nasync function createNestedDirectories(path: string, existingRoot: string) {\n const missing: string[] = [];\n let current = path;\n while (current !== existingRoot) {\n try {\n const stats = await lstat(current);\n if (stats.isSymbolicLink() || !stats.isDirectory()) {\n throw new PrototypeDuplicateError(\"filesystem\");\n }\n break;\n } catch (error) {\n if (error instanceof PrototypeDuplicateError) throw error;\n if (!isFileNotFound(error)) {\n throw new PrototypeDuplicateError(\"filesystem\");\n }\n missing.push(current);\n const parent = dirname(current);\n if (parent === current) throw new PrototypeDuplicateError(\"filesystem\");\n current = parent;\n }\n }\n\n const owned: OwnedPath[] = [];\n for (const directory of missing.reverse()) {\n owned.push(await createDirectory(directory));\n }\n return owned;\n}\n\nasync function writeExclusive(\n path: string,\n content: Uint8Array | string,\n writeFile: SafeWriteFile,\n) {\n try {\n await writeFile(path, content, { flag: \"wx\" });\n return await ownedPath(path);\n } catch {\n throw new PrototypeDuplicateError(\"filesystem\");\n }\n}\n\nasync function removeOwnedPaths(\n files: readonly OwnedPath[],\n directories: readonly OwnedPath[],\n) {\n try {\n for (const owned of [...files].reverse()) {\n const current = await lstat(owned.path).catch(() => null);\n if (\n current !== null &&\n !current.isSymbolicLink() &&\n current.dev === owned.device &&\n current.ino === owned.inode\n ) {\n await rm(owned.path, { force: true });\n }\n }\n for (const owned of [...directories].reverse()) {\n const current = await lstat(owned.path).catch(() => null);\n if (\n current !== null &&\n current.isDirectory() &&\n !current.isSymbolicLink() &&\n current.dev === owned.device &&\n current.ino === owned.inode\n ) {\n await rmdir(owned.path);\n }\n }\n } catch {\n throw new PrototypeDuplicateError(\"filesystem\");\n }\n}\n\nexport async function duplicatePrototype({\n paths,\n source,\n destination: destinationRef,\n title,\n description,\n authorName,\n themeRegistry,\n clock = () => new Date(),\n writeFile = writeFileAsync,\n}: DuplicatePrototypeOptions): Promise<OwnedDestinationResult> {\n const normalizedSource = definePrototypeRef(source);\n const normalizedDestination = definePrototypeRef(destinationRef);\n const sourcePath = sourcePathFor(paths.prototypeRoot, normalizedSource);\n const destination = sourcePathFor(paths.prototypeRoot, normalizedDestination);\n const sourceDetails = await inspectSource(sourcePath, themeRegistry);\n if (sourceDetails.metadata.authorLogin !== normalizedSource.login) {\n throw new PrototypeDuplicateError(\"invalid-source\");\n }\n\n const timestamp = clock().toISOString();\n const metadata = buildMetadataJson(\n title,\n description,\n normalizedDestination.login,\n authorName,\n timestamp,\n sourceDetails.metadata.theme,\n );\n parsePrototypeMetadata(JSON.parse(metadata), { themeRegistry });\n\n await ensureDirectory(paths.prototypeRoot);\n await ensureDirectory(dirname(destination));\n const ownedFiles: OwnedPath[] = [];\n const receipt = await reserveDestination(destination, paths);\n const ownedDirectories: OwnedPath[] = [receipt];\n\n try {\n ownedDirectories.push(\n await createDirectory(join(destination, \"components\")),\n );\n\n for (const name of COPYABLE_IMPLEMENTATION_FILES) {\n ownedFiles.push(\n await writeExclusive(\n join(destination, name),\n sourceDetails.implementationFiles.get(name)!,\n writeFile,\n ),\n );\n }\n\n if (sourceDetails.componentFiles.length === 0) {\n ownedFiles.push(\n await writeExclusive(\n join(destination, \"components/.gitkeep\"),\n \"\",\n writeFile,\n ),\n );\n } else {\n for (const file of sourceDetails.componentFiles) {\n const sourceContent = await readRequiredSourceFile(\n join(sourcePath, \"components\", file),\n );\n const target = join(destination, \"components\", file);\n ownedDirectories.push(\n ...(await createNestedDirectories(\n dirname(target),\n join(destination, \"components\"),\n )),\n );\n ownedFiles.push(await writeExclusive(target, sourceContent, writeFile));\n }\n }\n\n ownedFiles.push(\n await writeExclusive(\n join(destination, \"metadata.json\"),\n metadata,\n writeFile,\n ),\n );\n ownedFiles.push(\n await writeExclusive(\n join(destination, \"tsconfig.json\"),\n buildTsConfig(paths.repositoryRoot, destination),\n writeFile,\n ),\n );\n ownedFiles.push(\n await writeExclusive(\n join(destination, \"css-modules.d.ts\"),\n buildCssModulesDeclaration(),\n writeFile,\n ),\n );\n\n const writtenMetadata = await readNoFollow(\n join(destination, \"metadata.json\"),\n \"filesystem\",\n );\n if (writtenMetadata === null) {\n throw new PrototypeDuplicateError(\"filesystem\");\n }\n parsePrototypeMetadata(JSON.parse(writtenMetadata.toString(\"utf8\")), {\n themeRegistry,\n });\n const expectedFiles = [\n ...COPYABLE_IMPLEMENTATION_FILES,\n ...sourceDetails.componentFiles.map((file) => join(\"components\", file)),\n ...(sourceDetails.componentFiles.length === 0\n ? [\"components/.gitkeep\"]\n : []),\n \"metadata.json\",\n \"tsconfig.json\",\n \"css-modules.d.ts\",\n ];\n return {\n destination,\n receipt,\n expectedFiles: Object.freeze(expectedFiles),\n };\n } catch (error) {\n try {\n await removeOwnedPaths(ownedFiles, ownedDirectories);\n } catch {\n throw new PrototypeDuplicateError(\"filesystem\");\n }\n if (error instanceof PrototypeDuplicateError) throw error;\n throw new PrototypeDuplicateError(\"filesystem\");\n }\n}\n"]}
package/dist/duplicate.js CHANGED
@@ -4,6 +4,7 @@ import { dirname, join, relative } from "node:path";
4
4
  import { definePrototypeRef, parsePrototypeMetadata, } from "@ebay-dt/bonfire-core";
5
5
  import { buildCssModulesDeclaration, buildMetadataJson, buildTsConfig, COPYABLE_IMPLEMENTATION_FILES, } from "./internal/prototype-templates.js";
6
6
  import { captureOwnedDestination, } from "./internal/owned-destination.js";
7
+ import { isFileNotFound } from "./internal/utils.js";
7
8
  const FILE_OPEN_FLAGS = constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0);
8
9
  const BLOCKED_COMPONENT_NAMES = new Set([".next", "node_modules"]);
9
10
  export class PrototypeDuplicateError extends Error {
@@ -17,12 +18,6 @@ export class PrototypeDuplicateError extends Error {
17
18
  function sourcePathFor(root, ref) {
18
19
  return join(root, ref.login, ref.slug);
19
20
  }
20
- function isMissing(error) {
21
- return (error !== null &&
22
- typeof error === "object" &&
23
- "code" in error &&
24
- error.code === "ENOENT");
25
- }
26
21
  async function ownedPath(path) {
27
22
  const stats = await lstat(path);
28
23
  return { path, device: stats.dev, inode: stats.ino };
@@ -37,7 +32,7 @@ async function assertDirectory(path, kind) {
37
32
  catch (error) {
38
33
  if (error instanceof PrototypeDuplicateError)
39
34
  throw error;
40
- if (isMissing(error))
35
+ if (isFileNotFound(error))
41
36
  throw new PrototypeDuplicateError(kind);
42
37
  throw new PrototypeDuplicateError("filesystem");
43
38
  }
@@ -59,7 +54,7 @@ async function readNoFollow(path, kind) {
59
54
  catch (error) {
60
55
  if (error instanceof PrototypeDuplicateError)
61
56
  throw error;
62
- if (isMissing(error))
57
+ if (isFileNotFound(error))
63
58
  return null;
64
59
  throw new PrototypeDuplicateError(kind);
65
60
  }
@@ -108,7 +103,7 @@ async function listComponentFiles(root, current) {
108
103
  }
109
104
  return files;
110
105
  }
111
- async function inspectSource(sourcePath) {
106
+ async function inspectSource(sourcePath, themeRegistry) {
112
107
  await assertDirectory(sourcePath, "source-not-found");
113
108
  try {
114
109
  await lstat(join(sourcePath, "page.module.css"));
@@ -117,13 +112,14 @@ async function inspectSource(sourcePath) {
117
112
  catch (error) {
118
113
  if (error instanceof PrototypeDuplicateError)
119
114
  throw error;
120
- if (!isMissing(error))
115
+ if (!isFileNotFound(error)) {
121
116
  throw new PrototypeDuplicateError("invalid-source");
117
+ }
122
118
  }
123
119
  const metadataBytes = await readRequiredSourceFile(join(sourcePath, "metadata.json"));
124
120
  let metadata;
125
121
  try {
126
- metadata = parsePrototypeMetadata(JSON.parse(metadataBytes.toString("utf8")));
122
+ metadata = parsePrototypeMetadata(JSON.parse(metadataBytes.toString("utf8")), { themeRegistry });
127
123
  }
128
124
  catch {
129
125
  throw new PrototypeDuplicateError("invalid-source");
@@ -144,8 +140,9 @@ async function inspectSource(sourcePath) {
144
140
  catch (error) {
145
141
  if (error instanceof PrototypeDuplicateError)
146
142
  throw error;
147
- if (!isMissing(error))
143
+ if (!isFileNotFound(error)) {
148
144
  throw new PrototypeDuplicateError("invalid-source");
145
+ }
149
146
  }
150
147
  return { metadata, implementationFiles, componentFiles };
151
148
  }
@@ -211,8 +208,9 @@ async function createNestedDirectories(path, existingRoot) {
211
208
  catch (error) {
212
209
  if (error instanceof PrototypeDuplicateError)
213
210
  throw error;
214
- if (!isMissing(error))
211
+ if (!isFileNotFound(error)) {
215
212
  throw new PrototypeDuplicateError("filesystem");
213
+ }
216
214
  missing.push(current);
217
215
  const parent = dirname(current);
218
216
  if (parent === current)
@@ -261,18 +259,18 @@ async function removeOwnedPaths(files, directories) {
261
259
  throw new PrototypeDuplicateError("filesystem");
262
260
  }
263
261
  }
264
- export async function duplicatePrototype({ paths, source, destination: destinationRef, title, description, authorName, clock = () => new Date(), writeFile = writeFileAsync, }) {
262
+ export async function duplicatePrototype({ paths, source, destination: destinationRef, title, description, authorName, themeRegistry, clock = () => new Date(), writeFile = writeFileAsync, }) {
265
263
  const normalizedSource = definePrototypeRef(source);
266
264
  const normalizedDestination = definePrototypeRef(destinationRef);
267
265
  const sourcePath = sourcePathFor(paths.prototypeRoot, normalizedSource);
268
266
  const destination = sourcePathFor(paths.prototypeRoot, normalizedDestination);
269
- const sourceDetails = await inspectSource(sourcePath);
267
+ const sourceDetails = await inspectSource(sourcePath, themeRegistry);
270
268
  if (sourceDetails.metadata.authorLogin !== normalizedSource.login) {
271
269
  throw new PrototypeDuplicateError("invalid-source");
272
270
  }
273
271
  const timestamp = clock().toISOString();
274
- const metadata = buildMetadataJson(title, description, normalizedDestination.login, authorName, timestamp);
275
- parsePrototypeMetadata(JSON.parse(metadata));
272
+ const metadata = buildMetadataJson(title, description, normalizedDestination.login, authorName, timestamp, sourceDetails.metadata.theme);
273
+ parsePrototypeMetadata(JSON.parse(metadata), { themeRegistry });
276
274
  await ensureDirectory(paths.prototypeRoot);
277
275
  await ensureDirectory(dirname(destination));
278
276
  const ownedFiles = [];
@@ -301,7 +299,9 @@ export async function duplicatePrototype({ paths, source, destination: destinati
301
299
  if (writtenMetadata === null) {
302
300
  throw new PrototypeDuplicateError("filesystem");
303
301
  }
304
- parsePrototypeMetadata(JSON.parse(writtenMetadata.toString("utf8")));
302
+ parsePrototypeMetadata(JSON.parse(writtenMetadata.toString("utf8")), {
303
+ themeRegistry,
304
+ });
305
305
  const expectedFiles = [
306
306
  ...COPYABLE_IMPLEMENTATION_FILES,
307
307
  ...sourceDetails.componentFiles.map((file) => join("components", file)),
@@ -1 +1 @@
1
- {"version":3,"file":"duplicate.js","sourceRoot":"","sources":["../src/duplicate.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"duplicate.js","sourceRoot":"","sources":["../src/duplicate.ts"],"names":[],"mappings":"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","sourcesContent":["import { constants } from \"node:fs\";\nimport {\n lstat,\n mkdir,\n open,\n readdir,\n rm,\n rmdir,\n writeFile as writeFileAsync,\n} from \"node:fs/promises\";\nimport { dirname, join, relative } from \"node:path\";\nimport type { Dirent } from \"node:fs\";\nimport {\n definePrototypeRef,\n parsePrototypeMetadata,\n type PrototypeMetadata,\n type PrototypeRef,\n type ThemeRegistry,\n} from \"@ebay-dt/bonfire-core\";\nimport {\n buildCssModulesDeclaration,\n buildMetadataJson,\n buildTsConfig,\n COPYABLE_IMPLEMENTATION_FILES,\n} from \"./internal/prototype-templates.js\";\nimport {\n captureOwnedDestination,\n type OwnedDestinationResult,\n} from \"./internal/owned-destination.js\";\nimport type { ResolvedPrototypeCatalogPaths } from \"./prototype-paths.js\";\nimport { isFileNotFound } from \"./internal/utils.js\";\n\nconst FILE_OPEN_FLAGS = constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0);\nconst BLOCKED_COMPONENT_NAMES = new Set([\".next\", \"node_modules\"]);\n\ntype SafeWriteFile = (\n path: string,\n content: Uint8Array | string,\n options: { flag: \"wx\" },\n) => Promise<void>;\n\nexport type DuplicatePrototypeOptions = {\n paths: Pick<\n ResolvedPrototypeCatalogPaths,\n \"repositoryRoot\" | \"prototypeRoot\"\n >;\n source: PrototypeRef;\n destination: PrototypeRef;\n title: string;\n description: string | null;\n authorName: string | null;\n themeRegistry?: ThemeRegistry;\n clock?: () => Date;\n writeFile?: SafeWriteFile;\n};\n\nexport type PrototypeDuplicateErrorKind =\n \"source-not-found\" | \"invalid-source\" | \"collision\" | \"filesystem\";\n\nexport class PrototypeDuplicateError extends Error {\n readonly kind: PrototypeDuplicateErrorKind;\n\n constructor(kind: PrototypeDuplicateErrorKind) {\n super(`Prototype duplication failed: ${kind}`);\n this.name = \"PrototypeDuplicateError\";\n this.kind = kind;\n }\n}\n\ntype OwnedPath = {\n path: string;\n device: number;\n inode: number;\n};\n\nfunction sourcePathFor(root: string, ref: PrototypeRef) {\n return join(root, ref.login, ref.slug);\n}\n\nasync function ownedPath(path: string): Promise<OwnedPath> {\n const stats = await lstat(path);\n return { path, device: stats.dev, inode: stats.ino };\n}\n\nasync function assertDirectory(\n path: string,\n kind: \"source-not-found\" | \"invalid-source\" | \"filesystem\",\n) {\n try {\n const stats = await lstat(path);\n if (stats.isSymbolicLink() || !stats.isDirectory()) {\n throw new PrototypeDuplicateError(kind);\n }\n } catch (error) {\n if (error instanceof PrototypeDuplicateError) throw error;\n if (isFileNotFound(error)) throw new PrototypeDuplicateError(kind);\n throw new PrototypeDuplicateError(\"filesystem\");\n }\n}\n\nasync function readNoFollow(\n path: string,\n kind: \"invalid-source\" | \"filesystem\",\n) {\n try {\n const stats = await lstat(path);\n if (stats.isSymbolicLink() || !stats.isFile()) {\n throw new PrototypeDuplicateError(kind);\n }\n const file = await open(path, FILE_OPEN_FLAGS);\n try {\n return await file.readFile();\n } finally {\n await file.close();\n }\n } catch (error) {\n if (error instanceof PrototypeDuplicateError) throw error;\n if (isFileNotFound(error)) return null;\n throw new PrototypeDuplicateError(kind);\n }\n}\n\nasync function readRequiredSourceFile(path: string) {\n const content = await readNoFollow(path, \"invalid-source\");\n if (content === null) {\n throw new PrototypeDuplicateError(\"invalid-source\");\n }\n return content;\n}\n\nasync function listComponentFiles(\n root: string,\n current: string,\n): Promise<string[]> {\n let entries: Dirent[];\n try {\n entries = await readdir(current, { withFileTypes: true });\n } catch {\n throw new PrototypeDuplicateError(\"invalid-source\");\n }\n\n const files: string[] = [];\n for (const entry of entries.sort((left, right) =>\n left.name.localeCompare(right.name),\n )) {\n const path = join(current, entry.name);\n let stats;\n try {\n stats = await lstat(path);\n } catch {\n throw new PrototypeDuplicateError(\"invalid-source\");\n }\n if (stats.isSymbolicLink()) {\n throw new PrototypeDuplicateError(\"invalid-source\");\n }\n if (\n entry.name === \".gitkeep\" ||\n BLOCKED_COMPONENT_NAMES.has(entry.name) ||\n entry.name.startsWith(\".env\")\n ) {\n continue;\n }\n if (stats.isDirectory()) {\n files.push(...(await listComponentFiles(root, path)));\n continue;\n }\n if (!stats.isFile()) {\n throw new PrototypeDuplicateError(\"invalid-source\");\n }\n files.push(relative(root, path));\n }\n return files;\n}\n\nasync function inspectSource(\n sourcePath: string,\n themeRegistry?: ThemeRegistry,\n) {\n await assertDirectory(sourcePath, \"source-not-found\");\n\n try {\n await lstat(join(sourcePath, \"page.module.css\"));\n throw new PrototypeDuplicateError(\"invalid-source\");\n } catch (error) {\n if (error instanceof PrototypeDuplicateError) throw error;\n if (!isFileNotFound(error)) {\n throw new PrototypeDuplicateError(\"invalid-source\");\n }\n }\n\n const metadataBytes = await readRequiredSourceFile(\n join(sourcePath, \"metadata.json\"),\n );\n let metadata: PrototypeMetadata;\n try {\n metadata = parsePrototypeMetadata(\n JSON.parse(metadataBytes.toString(\"utf8\")),\n { themeRegistry },\n );\n } catch {\n throw new PrototypeDuplicateError(\"invalid-source\");\n }\n\n const implementationFiles = new Map<string, Uint8Array>();\n for (const name of COPYABLE_IMPLEMENTATION_FILES) {\n implementationFiles.set(\n name,\n await readRequiredSourceFile(join(sourcePath, name)),\n );\n }\n\n const componentsPath = join(sourcePath, \"components\");\n let componentFiles: string[] = [];\n try {\n const stats = await lstat(componentsPath);\n if (stats.isSymbolicLink() || !stats.isDirectory()) {\n throw new PrototypeDuplicateError(\"invalid-source\");\n }\n componentFiles = await listComponentFiles(componentsPath, componentsPath);\n } catch (error) {\n if (error instanceof PrototypeDuplicateError) throw error;\n if (!isFileNotFound(error)) {\n throw new PrototypeDuplicateError(\"invalid-source\");\n }\n }\n\n return { metadata, implementationFiles, componentFiles };\n}\n\nasync function reserveDestination(\n path: string,\n paths: Pick<\n ResolvedPrototypeCatalogPaths,\n \"repositoryRoot\" | \"prototypeRoot\"\n >,\n) {\n try {\n await mkdir(path);\n } catch (error) {\n if (\n error !== null &&\n typeof error === \"object\" &&\n \"code\" in error &&\n error.code === \"EEXIST\"\n ) {\n throw new PrototypeDuplicateError(\"collision\");\n }\n throw new PrototypeDuplicateError(\"filesystem\");\n }\n try {\n return await captureOwnedDestination({\n path,\n repositoryRoot: paths.repositoryRoot,\n prototypeRoot: paths.prototypeRoot,\n });\n } catch {\n // The newly created path is retained because ownership was not proven.\n throw new PrototypeDuplicateError(\"filesystem\");\n }\n}\n\nasync function ensureDirectory(path: string) {\n try {\n await mkdir(path, { recursive: true });\n await assertDirectory(path, \"filesystem\");\n } catch (error) {\n if (error instanceof PrototypeDuplicateError) throw error;\n throw new PrototypeDuplicateError(\"filesystem\");\n }\n}\n\nasync function createDirectory(path: string) {\n try {\n await mkdir(path);\n await assertDirectory(path, \"filesystem\");\n return await ownedPath(path);\n } catch (error) {\n if (error instanceof PrototypeDuplicateError) throw error;\n throw new PrototypeDuplicateError(\"filesystem\");\n }\n}\n\nasync function createNestedDirectories(path: string, existingRoot: string) {\n const missing: string[] = [];\n let current = path;\n while (current !== existingRoot) {\n try {\n const stats = await lstat(current);\n if (stats.isSymbolicLink() || !stats.isDirectory()) {\n throw new PrototypeDuplicateError(\"filesystem\");\n }\n break;\n } catch (error) {\n if (error instanceof PrototypeDuplicateError) throw error;\n if (!isFileNotFound(error)) {\n throw new PrototypeDuplicateError(\"filesystem\");\n }\n missing.push(current);\n const parent = dirname(current);\n if (parent === current) throw new PrototypeDuplicateError(\"filesystem\");\n current = parent;\n }\n }\n\n const owned: OwnedPath[] = [];\n for (const directory of missing.reverse()) {\n owned.push(await createDirectory(directory));\n }\n return owned;\n}\n\nasync function writeExclusive(\n path: string,\n content: Uint8Array | string,\n writeFile: SafeWriteFile,\n) {\n try {\n await writeFile(path, content, { flag: \"wx\" });\n return await ownedPath(path);\n } catch {\n throw new PrototypeDuplicateError(\"filesystem\");\n }\n}\n\nasync function removeOwnedPaths(\n files: readonly OwnedPath[],\n directories: readonly OwnedPath[],\n) {\n try {\n for (const owned of [...files].reverse()) {\n const current = await lstat(owned.path).catch(() => null);\n if (\n current !== null &&\n !current.isSymbolicLink() &&\n current.dev === owned.device &&\n current.ino === owned.inode\n ) {\n await rm(owned.path, { force: true });\n }\n }\n for (const owned of [...directories].reverse()) {\n const current = await lstat(owned.path).catch(() => null);\n if (\n current !== null &&\n current.isDirectory() &&\n !current.isSymbolicLink() &&\n current.dev === owned.device &&\n current.ino === owned.inode\n ) {\n await rmdir(owned.path);\n }\n }\n } catch {\n throw new PrototypeDuplicateError(\"filesystem\");\n }\n}\n\nexport async function duplicatePrototype({\n paths,\n source,\n destination: destinationRef,\n title,\n description,\n authorName,\n themeRegistry,\n clock = () => new Date(),\n writeFile = writeFileAsync,\n}: DuplicatePrototypeOptions): Promise<OwnedDestinationResult> {\n const normalizedSource = definePrototypeRef(source);\n const normalizedDestination = definePrototypeRef(destinationRef);\n const sourcePath = sourcePathFor(paths.prototypeRoot, normalizedSource);\n const destination = sourcePathFor(paths.prototypeRoot, normalizedDestination);\n const sourceDetails = await inspectSource(sourcePath, themeRegistry);\n if (sourceDetails.metadata.authorLogin !== normalizedSource.login) {\n throw new PrototypeDuplicateError(\"invalid-source\");\n }\n\n const timestamp = clock().toISOString();\n const metadata = buildMetadataJson(\n title,\n description,\n normalizedDestination.login,\n authorName,\n timestamp,\n sourceDetails.metadata.theme,\n );\n parsePrototypeMetadata(JSON.parse(metadata), { themeRegistry });\n\n await ensureDirectory(paths.prototypeRoot);\n await ensureDirectory(dirname(destination));\n const ownedFiles: OwnedPath[] = [];\n const receipt = await reserveDestination(destination, paths);\n const ownedDirectories: OwnedPath[] = [receipt];\n\n try {\n ownedDirectories.push(\n await createDirectory(join(destination, \"components\")),\n );\n\n for (const name of COPYABLE_IMPLEMENTATION_FILES) {\n ownedFiles.push(\n await writeExclusive(\n join(destination, name),\n sourceDetails.implementationFiles.get(name)!,\n writeFile,\n ),\n );\n }\n\n if (sourceDetails.componentFiles.length === 0) {\n ownedFiles.push(\n await writeExclusive(\n join(destination, \"components/.gitkeep\"),\n \"\",\n writeFile,\n ),\n );\n } else {\n for (const file of sourceDetails.componentFiles) {\n const sourceContent = await readRequiredSourceFile(\n join(sourcePath, \"components\", file),\n );\n const target = join(destination, \"components\", file);\n ownedDirectories.push(\n ...(await createNestedDirectories(\n dirname(target),\n join(destination, \"components\"),\n )),\n );\n ownedFiles.push(await writeExclusive(target, sourceContent, writeFile));\n }\n }\n\n ownedFiles.push(\n await writeExclusive(\n join(destination, \"metadata.json\"),\n metadata,\n writeFile,\n ),\n );\n ownedFiles.push(\n await writeExclusive(\n join(destination, \"tsconfig.json\"),\n buildTsConfig(paths.repositoryRoot, destination),\n writeFile,\n ),\n );\n ownedFiles.push(\n await writeExclusive(\n join(destination, \"css-modules.d.ts\"),\n buildCssModulesDeclaration(),\n writeFile,\n ),\n );\n\n const writtenMetadata = await readNoFollow(\n join(destination, \"metadata.json\"),\n \"filesystem\",\n );\n if (writtenMetadata === null) {\n throw new PrototypeDuplicateError(\"filesystem\");\n }\n parsePrototypeMetadata(JSON.parse(writtenMetadata.toString(\"utf8\")), {\n themeRegistry,\n });\n const expectedFiles = [\n ...COPYABLE_IMPLEMENTATION_FILES,\n ...sourceDetails.componentFiles.map((file) => join(\"components\", file)),\n ...(sourceDetails.componentFiles.length === 0\n ? [\"components/.gitkeep\"]\n : []),\n \"metadata.json\",\n \"tsconfig.json\",\n \"css-modules.d.ts\",\n ];\n return {\n destination,\n receipt,\n expectedFiles: Object.freeze(expectedFiles),\n };\n } catch (error) {\n try {\n await removeOwnedPaths(ownedFiles, ownedDirectories);\n } catch {\n throw new PrototypeDuplicateError(\"filesystem\");\n }\n if (error instanceof PrototypeDuplicateError) throw error;\n throw new PrototypeDuplicateError(\"filesystem\");\n }\n}\n"]}
@@ -0,0 +1,16 @@
1
+ export type ExecutableAccess = (path: string, mode: number) => Promise<void>;
2
+ export type ExecutableResolverOptions = {
3
+ path?: string;
4
+ pathExtensions?: string;
5
+ platform?: NodeJS.Platform;
6
+ access?: ExecutableAccess;
7
+ };
8
+ export interface ExecutableResolverLike {
9
+ resolve(command: string): Promise<string | null>;
10
+ }
11
+ export declare class PathExecutableResolver implements ExecutableResolverLike {
12
+ #private;
13
+ constructor(options?: ExecutableResolverOptions);
14
+ resolve(command: string): Promise<string | null>;
15
+ }
16
+ //# sourceMappingURL=executable.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executable.d.ts","sourceRoot":"","sources":["../src/executable.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,gBAAgB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;AAE7E,MAAM,MAAM,yBAAyB,GAAG;IACtC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC;IAC3B,MAAM,CAAC,EAAE,gBAAgB,CAAC;CAC3B,CAAC;AAEF,MAAM,WAAW,sBAAsB;IACrC,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CAClD;AAuBD,qBAAa,sBAAuB,YAAW,sBAAsB;;IAMnE,YAAY,OAAO,GAAE,yBAA8B,EAQlD;IAEK,OAAO,CAAC,OAAO,EAAE,MAAM,0BAkC5B;CACF","sourcesContent":["import { constants } from \"node:fs\";\nimport { access } from \"node:fs/promises\";\nimport { posix, win32 } from \"node:path\";\n\nconst DEFAULT_WINDOWS_EXTENSIONS = \".COM;.EXE;.BAT;.CMD\";\n\nexport type ExecutableAccess = (path: string, mode: number) => Promise<void>;\n\nexport type ExecutableResolverOptions = {\n path?: string;\n pathExtensions?: string;\n platform?: NodeJS.Platform;\n access?: ExecutableAccess;\n};\n\nexport interface ExecutableResolverLike {\n resolve(command: string): Promise<string | null>;\n}\n\nfunction isWindows(platform: NodeJS.Platform) {\n return platform === \"win32\";\n}\n\nfunction commandCandidates(\n command: string,\n platform: NodeJS.Platform,\n pathExtensions: string,\n) {\n const pathApi = isWindows(platform) ? win32 : posix;\n const hasPath = command.includes(\"/\") || command.includes(\"\\\\\");\n if (hasPath || pathApi.extname(command) !== \"\") return [command];\n\n if (!isWindows(platform)) return [command];\n\n return pathExtensions\n .split(\";\")\n .filter(Boolean)\n .map((extension) => `${command}${extension}`);\n}\n\nexport class PathExecutableResolver implements ExecutableResolverLike {\n readonly #path: string;\n readonly #pathExtensions: string;\n readonly #platform: NodeJS.Platform;\n readonly #access: ExecutableAccess;\n\n constructor(options: ExecutableResolverOptions = {}) {\n this.#platform = options.platform ?? process.platform;\n this.#path = options.path ?? process.env.PATH ?? \"\";\n this.#pathExtensions =\n options.pathExtensions ??\n process.env.PATHEXT ??\n DEFAULT_WINDOWS_EXTENSIONS;\n this.#access = options.access ?? access;\n }\n\n async resolve(command: string) {\n if (command.length === 0) return null;\n\n const pathApi = isWindows(this.#platform) ? win32 : posix;\n const hasPath = command.includes(\"/\") || command.includes(\"\\\\\");\n if (pathApi.isAbsolute(command) || hasPath) {\n try {\n await this.#access(command, constants.X_OK);\n return command;\n } catch {\n return null;\n }\n }\n\n const candidates = commandCandidates(\n command,\n this.#platform,\n this.#pathExtensions,\n );\n const directories = this.#path.split(isWindows(this.#platform) ? \";\" : \":\");\n\n for (const directory of directories) {\n for (const candidate of candidates) {\n const executablePath = pathApi.join(directory || \".\", candidate);\n try {\n await this.#access(executablePath, constants.X_OK);\n return executablePath;\n } catch {\n // Keep searching the remaining PATH entries.\n }\n }\n }\n\n return null;\n }\n}\n"]}
@@ -0,0 +1,65 @@
1
+ import { constants } from "node:fs";
2
+ import { access } from "node:fs/promises";
3
+ import { posix, win32 } from "node:path";
4
+ const DEFAULT_WINDOWS_EXTENSIONS = ".COM;.EXE;.BAT;.CMD";
5
+ function isWindows(platform) {
6
+ return platform === "win32";
7
+ }
8
+ function commandCandidates(command, platform, pathExtensions) {
9
+ const pathApi = isWindows(platform) ? win32 : posix;
10
+ const hasPath = command.includes("/") || command.includes("\\");
11
+ if (hasPath || pathApi.extname(command) !== "")
12
+ return [command];
13
+ if (!isWindows(platform))
14
+ return [command];
15
+ return pathExtensions
16
+ .split(";")
17
+ .filter(Boolean)
18
+ .map((extension) => `${command}${extension}`);
19
+ }
20
+ export class PathExecutableResolver {
21
+ #path;
22
+ #pathExtensions;
23
+ #platform;
24
+ #access;
25
+ constructor(options = {}) {
26
+ this.#platform = options.platform ?? process.platform;
27
+ this.#path = options.path ?? process.env.PATH ?? "";
28
+ this.#pathExtensions =
29
+ options.pathExtensions ??
30
+ process.env.PATHEXT ??
31
+ DEFAULT_WINDOWS_EXTENSIONS;
32
+ this.#access = options.access ?? access;
33
+ }
34
+ async resolve(command) {
35
+ if (command.length === 0)
36
+ return null;
37
+ const pathApi = isWindows(this.#platform) ? win32 : posix;
38
+ const hasPath = command.includes("/") || command.includes("\\");
39
+ if (pathApi.isAbsolute(command) || hasPath) {
40
+ try {
41
+ await this.#access(command, constants.X_OK);
42
+ return command;
43
+ }
44
+ catch {
45
+ return null;
46
+ }
47
+ }
48
+ const candidates = commandCandidates(command, this.#platform, this.#pathExtensions);
49
+ const directories = this.#path.split(isWindows(this.#platform) ? ";" : ":");
50
+ for (const directory of directories) {
51
+ for (const candidate of candidates) {
52
+ const executablePath = pathApi.join(directory || ".", candidate);
53
+ try {
54
+ await this.#access(executablePath, constants.X_OK);
55
+ return executablePath;
56
+ }
57
+ catch {
58
+ // Keep searching the remaining PATH entries.
59
+ }
60
+ }
61
+ }
62
+ return null;
63
+ }
64
+ }
65
+ //# sourceMappingURL=executable.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executable.js","sourceRoot":"","sources":["../src/executable.ts"],"names":[],"mappings":"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","sourcesContent":["import { constants } from \"node:fs\";\nimport { access } from \"node:fs/promises\";\nimport { posix, win32 } from \"node:path\";\n\nconst DEFAULT_WINDOWS_EXTENSIONS = \".COM;.EXE;.BAT;.CMD\";\n\nexport type ExecutableAccess = (path: string, mode: number) => Promise<void>;\n\nexport type ExecutableResolverOptions = {\n path?: string;\n pathExtensions?: string;\n platform?: NodeJS.Platform;\n access?: ExecutableAccess;\n};\n\nexport interface ExecutableResolverLike {\n resolve(command: string): Promise<string | null>;\n}\n\nfunction isWindows(platform: NodeJS.Platform) {\n return platform === \"win32\";\n}\n\nfunction commandCandidates(\n command: string,\n platform: NodeJS.Platform,\n pathExtensions: string,\n) {\n const pathApi = isWindows(platform) ? win32 : posix;\n const hasPath = command.includes(\"/\") || command.includes(\"\\\\\");\n if (hasPath || pathApi.extname(command) !== \"\") return [command];\n\n if (!isWindows(platform)) return [command];\n\n return pathExtensions\n .split(\";\")\n .filter(Boolean)\n .map((extension) => `${command}${extension}`);\n}\n\nexport class PathExecutableResolver implements ExecutableResolverLike {\n readonly #path: string;\n readonly #pathExtensions: string;\n readonly #platform: NodeJS.Platform;\n readonly #access: ExecutableAccess;\n\n constructor(options: ExecutableResolverOptions = {}) {\n this.#platform = options.platform ?? process.platform;\n this.#path = options.path ?? process.env.PATH ?? \"\";\n this.#pathExtensions =\n options.pathExtensions ??\n process.env.PATHEXT ??\n DEFAULT_WINDOWS_EXTENSIONS;\n this.#access = options.access ?? access;\n }\n\n async resolve(command: string) {\n if (command.length === 0) return null;\n\n const pathApi = isWindows(this.#platform) ? win32 : posix;\n const hasPath = command.includes(\"/\") || command.includes(\"\\\\\");\n if (pathApi.isAbsolute(command) || hasPath) {\n try {\n await this.#access(command, constants.X_OK);\n return command;\n } catch {\n return null;\n }\n }\n\n const candidates = commandCandidates(\n command,\n this.#platform,\n this.#pathExtensions,\n );\n const directories = this.#path.split(isWindows(this.#platform) ? \";\" : \":\");\n\n for (const directory of directories) {\n for (const candidate of candidates) {\n const executablePath = pathApi.join(directory || \".\", candidate);\n try {\n await this.#access(executablePath, constants.X_OK);\n return executablePath;\n } catch {\n // Keep searching the remaining PATH entries.\n }\n }\n }\n\n return null;\n }\n}\n"]}