@intra-mart/accel 0.1.0 → 0.3.0-next.202605250439

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 (44) hide show
  1. package/README.md +67 -5
  2. package/assets/assets.tar.gz +0 -0
  3. package/dist/asset/deployer.d.ts +13 -0
  4. package/dist/asset/deployer.js +84 -13
  5. package/dist/asset/walker.js +2 -0
  6. package/dist/commands/attach.d.ts +9 -0
  7. package/dist/commands/attach.js +84 -3
  8. package/dist/commands/deploy.d.ts +26 -0
  9. package/dist/commands/deploy.js +188 -0
  10. package/dist/commands/init.d.ts +4 -0
  11. package/dist/commands/init.js +20 -1
  12. package/dist/core/condition-evaluator.js +7 -1
  13. package/dist/core/constants.d.ts +2 -0
  14. package/dist/core/constants.js +8 -1
  15. package/dist/core/types.d.ts +51 -1
  16. package/dist/core/types.js +2 -0
  17. package/dist/core/validators.d.ts +2 -1
  18. package/dist/core/validators.js +58 -25
  19. package/dist/core/variable-interpolator.js +1 -0
  20. package/dist/deploy/api-client.d.ts +15 -0
  21. package/dist/deploy/api-client.js +81 -0
  22. package/dist/deploy/target-scanner.d.ts +5 -0
  23. package/dist/deploy/target-scanner.js +20 -0
  24. package/dist/i18n/en.js +80 -4
  25. package/dist/i18n/ja.js +83 -7
  26. package/dist/i18n/zh_CN.js +83 -7
  27. package/dist/index.js +2 -0
  28. package/dist/interactive/credentials-prompts.d.ts +2 -0
  29. package/dist/interactive/credentials-prompts.js +43 -0
  30. package/dist/interactive/format.d.ts +2 -0
  31. package/dist/interactive/format.js +33 -0
  32. package/dist/interactive/next-steps.d.ts +8 -0
  33. package/dist/interactive/next-steps.js +22 -0
  34. package/dist/interactive/progress.d.ts +2 -0
  35. package/dist/interactive/progress.js +21 -0
  36. package/dist/interactive/prompts.d.ts +1 -0
  37. package/dist/interactive/prompts.js +74 -15
  38. package/dist/interactive/summary.d.ts +3 -0
  39. package/dist/interactive/summary.js +58 -0
  40. package/dist/utils/credentials.d.ts +5 -0
  41. package/dist/utils/credentials.js +25 -0
  42. package/dist/utils/gitignore.d.ts +1 -0
  43. package/dist/utils/gitignore.js +23 -0
  44. package/package.json +2 -2
@@ -0,0 +1,188 @@
1
+ import { defineCommand } from "citty";
2
+ import * as p from "@clack/prompts";
3
+ import { readFile } from "node:fs/promises";
4
+ import { basename } from "node:path";
5
+ import { detectLocale } from "../utils/locale-detect.js";
6
+ import { readSettings } from "../utils/settings-io.js";
7
+ import { getMessage } from "../i18n/index.js";
8
+ import { ensureCredentials as defaultEnsureCredentials } from "../interactive/credentials-prompts.js";
9
+ import { scanTargets as defaultScanTargets } from "../deploy/target-scanner.js";
10
+ import { createApiClient as defaultApiClientFactory, isDeployError, } from "../deploy/api-client.js";
11
+ export const toImmFileName = (zipPath) => {
12
+ const base = basename(zipPath);
13
+ return base.replace(/\.zip$/i, "") + ".imm";
14
+ };
15
+ const defaultPrompts = {
16
+ selectStaging: async (stagings, locale) => {
17
+ const res = await p.select({
18
+ message: getMessage("deploy.selectStaging", locale),
19
+ options: stagings.map((s) => ({
20
+ value: s.stagingId,
21
+ label: s.description
22
+ ? `${s.stagingId} (${s.description})`
23
+ : s.stagingId,
24
+ })),
25
+ });
26
+ if (p.isCancel(res))
27
+ process.exit(0);
28
+ return res;
29
+ },
30
+ selectZip: async (zips, locale) => {
31
+ const res = await p.select({
32
+ message: getMessage("deploy.selectZip", locale),
33
+ options: zips.map((z) => ({ value: z, label: basename(z) })),
34
+ });
35
+ if (p.isCancel(res))
36
+ process.exit(0);
37
+ return res;
38
+ },
39
+ description: async (locale) => {
40
+ const res = await p.text({
41
+ message: getMessage("deploy.descriptionPrompt", locale),
42
+ defaultValue: "",
43
+ initialValue: "",
44
+ });
45
+ if (p.isCancel(res))
46
+ process.exit(0);
47
+ return res;
48
+ },
49
+ confirm: async (info, locale) => {
50
+ p.note([
51
+ `${getMessage("deploy.confirm.endpoint", locale)}: ${info.endpoint}`,
52
+ `${getMessage("deploy.confirm.stagingId", locale)}: ${info.stagingId}`,
53
+ `${getMessage("deploy.confirm.sourceFile", locale)}: ${info.sourceFile}`,
54
+ `${getMessage("deploy.confirm.sentAs", locale)}: ${info.sentAs}`,
55
+ ].join("\n"));
56
+ const res = await p.confirm({
57
+ message: getMessage("deploy.confirm", locale),
58
+ initialValue: true,
59
+ });
60
+ if (p.isCancel(res))
61
+ process.exit(0);
62
+ return res;
63
+ },
64
+ };
65
+ const resolveLocale = async (projectDir) => {
66
+ try {
67
+ const settings = await readSettings(projectDir);
68
+ return settings.locale ?? detectLocale();
69
+ }
70
+ catch {
71
+ return detectLocale();
72
+ }
73
+ };
74
+ const formatDeployError = (err, locale) => {
75
+ if (err.kind === "network") {
76
+ return getMessage("deploy.error.network", locale, {
77
+ message: err.serverMessage ?? "",
78
+ });
79
+ }
80
+ if (err.serverMessage) {
81
+ return getMessage("deploy.error.server", locale, {
82
+ message: err.serverMessage,
83
+ });
84
+ }
85
+ switch (err.status) {
86
+ case 401:
87
+ return getMessage("deploy.error.unauthorized", locale);
88
+ case 403:
89
+ return getMessage("deploy.error.forbidden", locale);
90
+ case 404:
91
+ return getMessage("deploy.error.notFound", locale);
92
+ case 400:
93
+ return getMessage("deploy.error.badRequest", locale);
94
+ case 500:
95
+ return getMessage("deploy.error.serverError", locale);
96
+ default:
97
+ return getMessage("deploy.error.unexpectedResponse", locale, {
98
+ status: String(err.status ?? "?"),
99
+ });
100
+ }
101
+ };
102
+ export const runDeploy = async (deps) => {
103
+ const { projectDir } = deps;
104
+ const locale = deps.locale ?? (await resolveLocale(projectDir));
105
+ const ensureCreds = deps.ensureCredentials ?? defaultEnsureCredentials;
106
+ const scan = deps.scanTargets ?? defaultScanTargets;
107
+ const apiClientFactory = deps.apiClientFactory ?? defaultApiClientFactory;
108
+ const prompts = deps.prompts ?? defaultPrompts;
109
+ p.intro(getMessage("deploy.intro", locale));
110
+ const creds = await ensureCreds(projectDir, locale);
111
+ const api = apiClientFactory(creds.endpoint, creds.apiKey);
112
+ const spin = p.spinner();
113
+ spin.start(getMessage("deploy.progress.fetchingStagings", locale));
114
+ let stagings;
115
+ try {
116
+ stagings = await api.listStagings();
117
+ }
118
+ catch (err) {
119
+ spin.stop(getMessage("deploy.progress.fetchingStagings", locale));
120
+ throw logAndRethrow(err, locale);
121
+ }
122
+ spin.stop(getMessage("deploy.progress.fetchingStagings", locale));
123
+ if (stagings.length === 0) {
124
+ p.log.error(getMessage("deploy.error.noStagings", locale));
125
+ throw new Error("no stagings");
126
+ }
127
+ const stagingId = await prompts.selectStaging(stagings, locale);
128
+ const zips = await scan(projectDir);
129
+ if (zips.length === 0) {
130
+ p.log.error(getMessage("deploy.error.noTargetZip", locale));
131
+ throw new Error("no target zip");
132
+ }
133
+ const zipPath = zips.length === 1 ? zips[0] : await prompts.selectZip(zips, locale);
134
+ const description = (await prompts.description(locale)).trim();
135
+ const immName = toImmFileName(zipPath);
136
+ const confirmed = await prompts.confirm({
137
+ endpoint: creds.endpoint,
138
+ stagingId,
139
+ sourceFile: basename(zipPath),
140
+ sentAs: immName,
141
+ }, locale);
142
+ if (!confirmed) {
143
+ p.log.info(getMessage("deploy.cancelled", locale));
144
+ return;
145
+ }
146
+ const bytes = await readFile(zipPath);
147
+ spin.start(getMessage("deploy.progress.deploying", locale));
148
+ let result;
149
+ try {
150
+ result = await api.createDeployment(stagingId, bytes, immName, description.length > 0 ? description : undefined);
151
+ }
152
+ catch (err) {
153
+ spin.stop(getMessage("deploy.progress.deploying", locale));
154
+ throw logAndRethrow(err, locale);
155
+ }
156
+ spin.stop(getMessage("deploy.progress.deploying", locale));
157
+ p.note([
158
+ `${getMessage("deploy.result.deployId", locale)}: ${result.deployId}`,
159
+ `${getMessage("deploy.result.stagingId", locale)}: ${result.stagingId}`,
160
+ `${getMessage("deploy.result.status", locale)}: ${result.status}`,
161
+ `${getMessage("deploy.result.createDate", locale)}: ${result.createDate}`,
162
+ ].join("\n"));
163
+ p.outro(getMessage("deploy.success", locale));
164
+ };
165
+ const logAndRethrow = (err, locale) => {
166
+ if (isDeployError(err)) {
167
+ p.log.error(formatDeployError(err, locale));
168
+ }
169
+ else {
170
+ p.log.error(err instanceof Error ? err.message : String(err));
171
+ }
172
+ return err;
173
+ };
174
+ export const deployCommand = defineCommand({
175
+ meta: {
176
+ name: "deploy",
177
+ description: "Deploy build artifacts to an iAP staging environment",
178
+ },
179
+ args: {},
180
+ run: async () => {
181
+ try {
182
+ await runDeploy({ projectDir: process.cwd() });
183
+ }
184
+ catch {
185
+ process.exit(1);
186
+ }
187
+ },
188
+ });
@@ -48,6 +48,10 @@ export declare const initCommand: import("citty").CommandDef<{
48
48
  type: "string";
49
49
  description: string;
50
50
  };
51
+ "package-manager": {
52
+ type: "string";
53
+ description: string;
54
+ };
51
55
  "git-init": {
52
56
  type: "boolean";
53
57
  description: string;
@@ -12,6 +12,9 @@ import { defaultAssetSourcePath } from "../asset/default-source.js";
12
12
  import { getMessage } from "../i18n/index.js";
13
13
  import { detectLocale } from "../utils/locale-detect.js";
14
14
  import { commandExists } from "../utils/command-exists.js";
15
+ import { printSummary } from "../interactive/summary.js";
16
+ import { printNextSteps } from "../interactive/next-steps.js";
17
+ import { buildProgressCallbacks } from "../interactive/progress.js";
15
18
  export const initCommand = defineCommand({
16
19
  meta: {
17
20
  name: "init",
@@ -67,6 +70,10 @@ export const initCommand = defineCommand({
67
70
  type: "string",
68
71
  description: "Maven artifactId (defaults to project name)",
69
72
  },
73
+ "package-manager": {
74
+ type: "string",
75
+ description: "Package manager (bun, npm, yarn, pnpm). Default: bun",
76
+ },
70
77
  "git-init": {
71
78
  type: "boolean",
72
79
  description: "Initialize git repository (use --no-git-init to disable)",
@@ -113,6 +120,7 @@ export const initCommand = defineCommand({
113
120
  agent: agentArg
114
121
  ? agentArg.split(",").map((a) => a.trim())
115
122
  : undefined,
123
+ packageManager: args["package-manager"],
116
124
  locale,
117
125
  withGit: args["git-init"],
118
126
  noInteraction: args["non-interactive"],
@@ -149,20 +157,25 @@ export const initCommand = defineCommand({
149
157
  agents: resolved.agents,
150
158
  javascript: resolved.javascript,
151
159
  locale: resolved.locale,
160
+ packageManager: resolved.packageManager,
152
161
  jugglingProject: resolved.jugglingProject,
153
162
  deployedAssets: {},
154
163
  };
164
+ const isInteractive = !args["non-interactive"];
165
+ if (isInteractive) {
166
+ printSummary(settings, projectDir, locale);
167
+ }
155
168
  const serverUrl = args["asset-server-url"];
156
169
  const assetSource = args["asset-source"] ?? defaultAssetSourcePath();
157
170
  const provider = serverUrl
158
171
  ? createLocalAssetProvider(serverUrl)
159
172
  : createFileAssetProvider(assetSource);
160
- p.log.info(getMessage("progress.deploying", locale));
161
173
  await deployAssets({
162
174
  projectDir,
163
175
  settings,
164
176
  provider,
165
177
  noInstall: args["skip-install"],
178
+ progress: buildProgressCallbacks(locale),
166
179
  });
167
180
  if (resolved.withGit) {
168
181
  if (commandExists("git")) {
@@ -179,5 +192,11 @@ export const initCommand = defineCommand({
179
192
  }
180
193
  }
181
194
  p.log.success(getMessage("progress.complete", locale));
195
+ printNextSteps({
196
+ projectDir,
197
+ agents: resolved.agents,
198
+ isInit: true,
199
+ locale,
200
+ });
182
201
  },
183
202
  });
@@ -1,5 +1,5 @@
1
1
  import { satisfies } from "semver";
2
- import { isAndCondition, isOrCondition, isVersionCondition, isModuleCondition, isLocaleCondition, isAgentCondition, } from "./types.js";
2
+ import { isAndCondition, isOrCondition, isVersionCondition, isModuleCondition, isLocaleCondition, isAgentCondition, isPackageManagerCondition, isJavascriptCondition, } from "./types.js";
3
3
  export const evaluateCondition = (condition, context) => {
4
4
  if (condition === undefined) {
5
5
  return true;
@@ -22,5 +22,11 @@ export const evaluateCondition = (condition, context) => {
22
22
  if (isAgentCondition(condition)) {
23
23
  return context.agents.includes(condition.agent);
24
24
  }
25
+ if (isPackageManagerCondition(condition)) {
26
+ return context.packageManager === condition.packageManager;
27
+ }
28
+ if (isJavascriptCondition(condition)) {
29
+ return context.javascript === condition.javascript;
30
+ }
25
31
  return false;
26
32
  };
@@ -8,4 +8,6 @@ export declare const MODULE_OPTIONS: readonly ["workflow", "bpm", "copilot", "im
8
8
  export type ModuleOption = (typeof MODULE_OPTIONS)[number];
9
9
  export declare const LOCALE_OPTIONS: readonly ["ja", "en", "zh_CN"];
10
10
  export type LocaleOption = (typeof LOCALE_OPTIONS)[number];
11
+ export declare const PACKAGE_MANAGER_OPTIONS: readonly ["bun", "npm", "yarn", "pnpm"];
12
+ export type PackageManagerOption = (typeof PACKAGE_MANAGER_OPTIONS)[number];
11
13
  export declare const DEFAULT_SETTINGS: Omit<AccelSettings, "cliVersion" | "createdAt" | "deployedAssets">;
@@ -10,17 +10,24 @@ export const MODULE_OPTIONS = [
10
10
  "kaiden",
11
11
  ];
12
12
  export const LOCALE_OPTIONS = ["ja", "en", "zh_CN"];
13
+ export const PACKAGE_MANAGER_OPTIONS = [
14
+ "bun",
15
+ "npm",
16
+ "yarn",
17
+ "pnpm",
18
+ ];
13
19
  export const DEFAULT_SETTINGS = {
14
20
  name: "my-accel-project",
15
21
  artifactId: "",
16
22
  group: "com.example",
17
23
  projectVersion: "0.1.0",
18
24
  description: "",
19
- accelplatformVersion: "2025-Autumn",
25
+ accelplatformVersion: "2026-Spring",
20
26
  modules: [],
21
27
  database: "postgresql",
22
28
  agents: ["claude-code", "github-copilot"],
23
29
  javascript: false,
24
30
  locale: "ja",
31
+ packageManager: "bun",
25
32
  jugglingProject: null,
26
33
  };
@@ -16,7 +16,13 @@ export type LocaleCondition = {
16
16
  export type AgentCondition = {
17
17
  agent: string;
18
18
  };
19
- export type LeafCondition = VersionCondition | ModuleCondition | LocaleCondition | AgentCondition;
19
+ export type PackageManagerCondition = {
20
+ packageManager: string;
21
+ };
22
+ export type JavascriptCondition = {
23
+ javascript: boolean;
24
+ };
25
+ export type LeafCondition = VersionCondition | ModuleCondition | LocaleCondition | AgentCondition | PackageManagerCondition | JavascriptCondition;
20
26
  export type Condition = AndCondition | OrCondition | LeafCondition;
21
27
  export type TextReplacement = {
22
28
  type: "text";
@@ -69,6 +75,7 @@ export type AccelSettings = {
69
75
  agents: string[];
70
76
  javascript: boolean;
71
77
  locale: string;
78
+ packageManager: string;
72
79
  jugglingProject: string | null;
73
80
  deployedAssets: Record<string, string>;
74
81
  };
@@ -93,6 +100,8 @@ export type EvalContext = {
93
100
  accelplatformVersion: string;
94
101
  database: string;
95
102
  projectVersion: string;
103
+ packageManager: string;
104
+ javascript: boolean;
96
105
  };
97
106
  export declare const isAndCondition: (c: Condition) => c is AndCondition;
98
107
  export declare const isOrCondition: (c: Condition) => c is OrCondition;
@@ -100,3 +109,44 @@ export declare const isVersionCondition: (c: Condition) => c is VersionCondition
100
109
  export declare const isModuleCondition: (c: Condition) => c is ModuleCondition;
101
110
  export declare const isLocaleCondition: (c: Condition) => c is LocaleCondition;
102
111
  export declare const isAgentCondition: (c: Condition) => c is AgentCondition;
112
+ export declare const isPackageManagerCondition: (c: Condition) => c is PackageManagerCondition;
113
+ export declare const isJavascriptCondition: (c: Condition) => c is JavascriptCondition;
114
+ export type AccelCredentials = {
115
+ endpoint: string;
116
+ apiKey: string;
117
+ };
118
+ export type StagingResponse = {
119
+ stagingId: string;
120
+ description?: string | null;
121
+ currentDeployId?: string | null;
122
+ createUserCd: string;
123
+ createDate: string;
124
+ };
125
+ export type StagingListResponse = {
126
+ totalCount: number;
127
+ offset: number;
128
+ limit: number;
129
+ records: StagingResponse[];
130
+ };
131
+ export type DeploymentResponse = {
132
+ deployId: string;
133
+ stagingId: string;
134
+ status: "STAGED" | "UNDEPLOYED";
135
+ description?: string | null;
136
+ createUserCd: string;
137
+ createDate: string;
138
+ };
139
+ export type ApiSuccess<T> = {
140
+ error: false;
141
+ data: T;
142
+ };
143
+ export type ApiErrorBody = {
144
+ error: true;
145
+ errorMessage: string;
146
+ };
147
+ export type DeployError = {
148
+ _tag: "DeployError";
149
+ kind: "network" | "http";
150
+ status?: number;
151
+ serverMessage?: string;
152
+ };
@@ -4,3 +4,5 @@ export const isVersionCondition = (c) => "version" in c && !("and" in c) && !("o
4
4
  export const isModuleCondition = (c) => "module" in c;
5
5
  export const isLocaleCondition = (c) => "locale" in c;
6
6
  export const isAgentCondition = (c) => "agent" in c;
7
+ export const isPackageManagerCondition = (c) => "packageManager" in c;
8
+ export const isJavascriptCondition = (c) => "javascript" in c;
@@ -1,4 +1,4 @@
1
- export type Validator = (value: string) => string | undefined;
1
+ export type Validator = (value: string | undefined) => string | undefined;
2
2
  export type Validators = {
3
3
  name: Validator;
4
4
  artifactId: Validator;
@@ -8,5 +8,6 @@ export type Validators = {
8
8
  module: Validator;
9
9
  database: Validator;
10
10
  agent: Validator;
11
+ packageManager: Validator;
11
12
  };
12
13
  export declare const createValidators: (locale: string) => Validators;
@@ -1,5 +1,5 @@
1
1
  import { getMessage } from "../i18n/index.js";
2
- import { AGENT_OPTIONS, DATABASE_OPTIONS, MODULE_OPTIONS, } from "./constants.js";
2
+ import { AGENT_OPTIONS, DATABASE_OPTIONS, MODULE_OPTIONS, PACKAGE_MANAGER_OPTIONS, } from "./constants.js";
3
3
  import { SELECTABLE_VERSIONS } from "./version-map.js";
4
4
  const ARTIFACT_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
5
5
  const GROUP_PATTERN = /^[A-Za-z_$][\w$]*(\.[A-Za-z_$][\w$]*)*$/;
@@ -23,29 +23,62 @@ const isValidVersionLabel = (value) => SELECTABLE_VERSIONS.some((v) => v.label =
23
23
  const isValidModule = (value) => MODULE_OPTIONS.includes(value);
24
24
  const isValidDatabase = (value) => DATABASE_OPTIONS.includes(value);
25
25
  const isValidAgent = (value) => AGENT_OPTIONS.includes(value);
26
+ const isValidPackageManager = (value) => PACKAGE_MANAGER_OPTIONS.includes(value);
26
27
  export const createValidators = (locale) => ({
27
- name: (value) => isValidName(value)
28
- ? undefined
29
- : getMessage("error.invalidName", locale, { value }),
30
- artifactId: (value) => isValidArtifactId(value)
31
- ? undefined
32
- : getMessage("error.invalidArtifactId", locale, { value }),
33
- group: (value) => isValidGroup(value)
34
- ? undefined
35
- : getMessage("error.invalidGroup", locale, { value }),
36
- projectVersion: (value) => isValidProjectVersion(value)
37
- ? undefined
38
- : getMessage("error.invalidProjectVersion", locale, { value }),
39
- versionLabel: (value) => isValidVersionLabel(value)
40
- ? undefined
41
- : getMessage("error.invalidVersion", locale, { version: value }),
42
- module: (value) => isValidModule(value)
43
- ? undefined
44
- : getMessage("error.invalidModule", locale, { module: value }),
45
- database: (value) => isValidDatabase(value)
46
- ? undefined
47
- : getMessage("error.invalidDatabase", locale, { database: value }),
48
- agent: (value) => isValidAgent(value)
49
- ? undefined
50
- : getMessage("error.invalidAgent", locale, { agent: value }),
28
+ name: (value) => {
29
+ const v = value ?? "";
30
+ return isValidName(v)
31
+ ? undefined
32
+ : getMessage("error.invalidName", locale, { value: v });
33
+ },
34
+ artifactId: (value) => {
35
+ const v = value ?? "";
36
+ return isValidArtifactId(v)
37
+ ? undefined
38
+ : getMessage("error.invalidArtifactId", locale, { value: v });
39
+ },
40
+ group: (value) => {
41
+ const v = value ?? "";
42
+ return isValidGroup(v)
43
+ ? undefined
44
+ : getMessage("error.invalidGroup", locale, { value: v });
45
+ },
46
+ projectVersion: (value) => {
47
+ const v = value ?? "";
48
+ return isValidProjectVersion(v)
49
+ ? undefined
50
+ : getMessage("error.invalidProjectVersion", locale, { value: v });
51
+ },
52
+ versionLabel: (value) => {
53
+ const v = value ?? "";
54
+ return isValidVersionLabel(v)
55
+ ? undefined
56
+ : getMessage("error.invalidVersion", locale, { version: v });
57
+ },
58
+ module: (value) => {
59
+ const v = value ?? "";
60
+ return isValidModule(v)
61
+ ? undefined
62
+ : getMessage("error.invalidModule", locale, { module: v });
63
+ },
64
+ database: (value) => {
65
+ const v = value ?? "";
66
+ return isValidDatabase(v)
67
+ ? undefined
68
+ : getMessage("error.invalidDatabase", locale, { database: v });
69
+ },
70
+ agent: (value) => {
71
+ const v = value ?? "";
72
+ return isValidAgent(v)
73
+ ? undefined
74
+ : getMessage("error.invalidAgent", locale, { agent: v });
75
+ },
76
+ packageManager: (value) => {
77
+ const v = value ?? "";
78
+ return isValidPackageManager(v)
79
+ ? undefined
80
+ : getMessage("error.invalidPackageManager", locale, {
81
+ packageManager: v,
82
+ });
83
+ },
51
84
  });
@@ -8,6 +8,7 @@ const VARIABLE_MAP = new Map([
8
8
  ["locale", "locale"],
9
9
  ["database", "database"],
10
10
  ["projectVersion", "projectVersion"],
11
+ ["packageManager", "packageManager"],
11
12
  ]);
12
13
  const INTERPOLATION_PATTERN = /\{\{\$(\w+)\}\}/g;
13
14
  export const interpolateVariables = (template, context) => {
@@ -0,0 +1,15 @@
1
+ import type { StagingResponse, DeploymentResponse, DeployError } from "../core/types.js";
2
+ type FetchFn = typeof globalThis.fetch;
3
+ export declare const makeDeployError: (kind: DeployError["kind"], extra?: {
4
+ status?: number;
5
+ serverMessage?: string;
6
+ }) => DeployError;
7
+ export declare const isDeployError: (e: unknown) => e is DeployError;
8
+ export type ApiClient = {
9
+ listStagings: () => Promise<StagingResponse[]>;
10
+ createDeployment: (stagingId: string, bytes: Uint8Array, immFileName: string, description?: string) => Promise<DeploymentResponse>;
11
+ };
12
+ export declare const createApiClient: (endpoint: string, apiKey: string, deps?: {
13
+ fetch?: FetchFn;
14
+ }) => ApiClient;
15
+ export {};
@@ -0,0 +1,81 @@
1
+ const STAGING_PATH = "/api/bearer/development/staging";
2
+ const PAGE_LIMIT = 100;
3
+ const MAX_PAGES = 1000;
4
+ export const makeDeployError = (kind, extra = {}) => ({ _tag: "DeployError", kind, ...extra });
5
+ export const isDeployError = (e) => typeof e === "object" &&
6
+ e !== null &&
7
+ e._tag === "DeployError";
8
+ export const createApiClient = (endpoint, apiKey, deps = {}) => {
9
+ const doFetch = deps.fetch ?? globalThis.fetch;
10
+ const baseHeaders = {
11
+ "X-Intramart-Session": "never",
12
+ Authorization: `Bearer ${apiKey}`,
13
+ };
14
+ const request = async (url, init) => {
15
+ let res;
16
+ try {
17
+ res = await doFetch(url, init);
18
+ }
19
+ catch (err) {
20
+ throw makeDeployError("network", {
21
+ serverMessage: err instanceof Error ? err.message : String(err),
22
+ });
23
+ }
24
+ const text = await res.text();
25
+ let body;
26
+ try {
27
+ body = text.length > 0 ? JSON.parse(text) : undefined;
28
+ }
29
+ catch {
30
+ throw makeDeployError("http", { status: res.status });
31
+ }
32
+ if (body !== null &&
33
+ typeof body === "object" &&
34
+ body.error === true) {
35
+ throw makeDeployError("http", {
36
+ status: res.status,
37
+ serverMessage: body.errorMessage,
38
+ });
39
+ }
40
+ if (!res.ok) {
41
+ throw makeDeployError("http", { status: res.status });
42
+ }
43
+ if (body !== null &&
44
+ typeof body === "object" &&
45
+ "data" in body) {
46
+ return body.data;
47
+ }
48
+ throw makeDeployError("http", { status: res.status });
49
+ };
50
+ const listStagings = async () => {
51
+ const records = [];
52
+ let offset = 0;
53
+ for (let page = 0; page < MAX_PAGES; page++) {
54
+ const url = `${endpoint}${STAGING_PATH}?offset=${offset}&limit=${PAGE_LIMIT}`;
55
+ const data = await request(url, {
56
+ method: "GET",
57
+ headers: baseHeaders,
58
+ });
59
+ records.push(...data.records);
60
+ if (records.length >= data.totalCount || data.records.length === 0) {
61
+ break;
62
+ }
63
+ offset += PAGE_LIMIT;
64
+ }
65
+ return records;
66
+ };
67
+ const createDeployment = async (stagingId, bytes, immFileName, description) => {
68
+ const form = new FormData();
69
+ form.append("archiveFile", new File([bytes], immFileName, { type: "application/zip" }));
70
+ if (description && description.length > 0) {
71
+ form.append("description", description);
72
+ }
73
+ const url = `${endpoint}${STAGING_PATH}/${encodeURIComponent(stagingId)}/deploy`;
74
+ return request(url, {
75
+ method: "POST",
76
+ headers: baseHeaders,
77
+ body: form,
78
+ });
79
+ };
80
+ return { listStagings, createDeployment };
81
+ };
@@ -0,0 +1,5 @@
1
+ export type ScanOptions = {
2
+ dir?: string;
3
+ pattern?: RegExp;
4
+ };
5
+ export declare const scanTargets: (projectDir: string, opts?: ScanOptions) => Promise<string[]>;
@@ -0,0 +1,20 @@
1
+ import { readdir } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ const DEFAULT_DIR = "target";
4
+ const DEFAULT_PATTERN = /\.zip$/i;
5
+ export const scanTargets = async (projectDir, opts = {}) => {
6
+ const dir = opts.dir ?? DEFAULT_DIR;
7
+ const pattern = opts.pattern ?? DEFAULT_PATTERN;
8
+ const targetDir = join(projectDir, dir);
9
+ let entries;
10
+ try {
11
+ entries = await readdir(targetDir, { withFileTypes: true });
12
+ }
13
+ catch {
14
+ return [];
15
+ }
16
+ return entries
17
+ .filter((e) => e.isFile() && pattern.test(e.name))
18
+ .map((e) => join(targetDir, e.name))
19
+ .sort();
20
+ };