naro-cli 0.1.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/artifact-types.d.ts +1 -0
- package/dist/{chunk-63SYN66G.js → chunk-IC4R5EYE.js} +332 -64
- package/dist/deploy.d.ts +9 -0
- package/dist/deploy.js +3 -1
- package/dist/git-info.d.ts +7 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +12 -79
- package/package.json +3 -3
package/dist/artifact-types.d.ts
CHANGED
|
@@ -28,6 +28,7 @@ export interface BuildLog {
|
|
|
28
28
|
/** Mirrors the build metadata shape from the internal build package. */
|
|
29
29
|
export interface BuildMetadata {
|
|
30
30
|
gitCommitSha?: string;
|
|
31
|
+
gitCommitMessage?: string;
|
|
31
32
|
artifactKey?: string;
|
|
32
33
|
}
|
|
33
34
|
/** Mirrors the build observer shape from the internal build package. */
|
|
@@ -7,9 +7,9 @@ var __export = (target, all) => {
|
|
|
7
7
|
|
|
8
8
|
// src/deploy.ts
|
|
9
9
|
import { existsSync, readFileSync as readFileSync2 } from "fs";
|
|
10
|
-
import { cp, mkdtemp as mkdtemp2, readFile as
|
|
11
|
-
import { tmpdir as tmpdir2 } from "os";
|
|
12
|
-
import { basename, dirname, join as
|
|
10
|
+
import { cp, mkdtemp as mkdtemp2, readFile as readFile6, rm as rm2 } from "fs/promises";
|
|
11
|
+
import { homedir as homedir3, tmpdir as tmpdir2 } from "os";
|
|
12
|
+
import { basename, dirname, join as join9 } from "path";
|
|
13
13
|
import { fileURLToPath } from "url";
|
|
14
14
|
|
|
15
15
|
// ../../packages/build/src/cache.ts
|
|
@@ -107,18 +107,31 @@ async function saveCache(args) {
|
|
|
107
107
|
await log(observer, scope, "INFO", `Saved ${scope} cache (${key}).`);
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
+
// ../../packages/build/src/hash.ts
|
|
111
|
+
import { createHash as createHash2 } from "crypto";
|
|
112
|
+
function hashAsset(data) {
|
|
113
|
+
return createHash2("sha256").update(data).digest("hex").slice(0, 32);
|
|
114
|
+
}
|
|
115
|
+
|
|
110
116
|
// ../../packages/build/src/local-build-executor.ts
|
|
111
117
|
import { mkdtemp, rm } from "fs/promises";
|
|
112
118
|
import { tmpdir } from "os";
|
|
113
|
-
import { join as
|
|
119
|
+
import { join as join7 } from "path";
|
|
120
|
+
|
|
121
|
+
// ../../packages/core/src/artifact-manifest.ts
|
|
122
|
+
var MAX_FILE_BYTES = 25 * 1024 * 1024;
|
|
123
|
+
var MAX_ARTIFACT_BYTES = 64 * 1024 * 1024;
|
|
114
124
|
|
|
115
125
|
// ../../packages/core/src/errors.ts
|
|
116
126
|
var DeploymentError = class extends Error {
|
|
117
127
|
code;
|
|
128
|
+
/** HTTP status from the upstream response that caused this error, when known. */
|
|
129
|
+
status;
|
|
118
130
|
constructor(code, message, options) {
|
|
119
131
|
super(message, options);
|
|
120
132
|
this.name = "DeploymentError";
|
|
121
133
|
this.code = code;
|
|
134
|
+
if (options?.status !== void 0) this.status = options.status;
|
|
122
135
|
}
|
|
123
136
|
};
|
|
124
137
|
|
|
@@ -14636,6 +14649,41 @@ function date4(params) {
|
|
|
14636
14649
|
// ../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/external.js
|
|
14637
14650
|
config(en_default());
|
|
14638
14651
|
|
|
14652
|
+
// ../../packages/core/src/subdomain.ts
|
|
14653
|
+
var RESERVED_SUBDOMAINS = [
|
|
14654
|
+
"admin",
|
|
14655
|
+
"api",
|
|
14656
|
+
"app",
|
|
14657
|
+
"assets",
|
|
14658
|
+
"blog",
|
|
14659
|
+
"cdn",
|
|
14660
|
+
"dashboard",
|
|
14661
|
+
"docs",
|
|
14662
|
+
"help",
|
|
14663
|
+
"imap",
|
|
14664
|
+
"mail",
|
|
14665
|
+
"mx",
|
|
14666
|
+
"naro",
|
|
14667
|
+
"ns1",
|
|
14668
|
+
"ns2",
|
|
14669
|
+
"preview",
|
|
14670
|
+
"smtp",
|
|
14671
|
+
"static",
|
|
14672
|
+
"status",
|
|
14673
|
+
"support",
|
|
14674
|
+
"www"
|
|
14675
|
+
];
|
|
14676
|
+
var SUBDOMAIN_PATTERN = /^[a-z0-9](-?[a-z0-9])*$/;
|
|
14677
|
+
var SUBDOMAIN_MAX_LENGTH = 54;
|
|
14678
|
+
function subdomainProblem(value) {
|
|
14679
|
+
if (value.length < 1 || value.length > SUBDOMAIN_MAX_LENGTH) return "invalid";
|
|
14680
|
+
if (!SUBDOMAIN_PATTERN.test(value)) return "invalid";
|
|
14681
|
+
if (value.endsWith("-preview")) return "reserved";
|
|
14682
|
+
if (RESERVED_SUBDOMAINS.includes(value))
|
|
14683
|
+
return "reserved";
|
|
14684
|
+
return null;
|
|
14685
|
+
}
|
|
14686
|
+
|
|
14639
14687
|
// ../../packages/core/src/schemas.ts
|
|
14640
14688
|
function isSupportedGitUrl(value) {
|
|
14641
14689
|
if (/^git@[A-Za-z0-9.-]+:[A-Za-z0-9._/-]+(?:\.git)?$/.test(value)) {
|
|
@@ -14666,12 +14714,30 @@ var createDeploymentSchema = external_exports.object({
|
|
|
14666
14714
|
branch: external_exports.string().trim().max(240).optional().transform((value) => value || null)
|
|
14667
14715
|
});
|
|
14668
14716
|
var connectRepositorySchema = external_exports.object({
|
|
14717
|
+
// Web-only route context: the only consumer is apps/web's
|
|
14718
|
+
// POST /api/projects handler, which resolves this to a team id.
|
|
14719
|
+
teamSlug: external_exports.string().trim().min(1),
|
|
14669
14720
|
name: external_exports.string().trim().min(1).max(80),
|
|
14670
14721
|
installationId: external_exports.number().int().positive(),
|
|
14671
14722
|
repoId: external_exports.number().int().positive(),
|
|
14672
14723
|
fullName: external_exports.string().trim().min(1).max(200).regex(/^[^/]+\/[^/]+$/, { message: "fullName must be owner/name" }),
|
|
14673
14724
|
defaultBranch: external_exports.string().trim().min(1).max(240).default("main"),
|
|
14674
|
-
rootDirectory: optionalRootDirectory
|
|
14725
|
+
rootDirectory: optionalRootDirectory,
|
|
14726
|
+
subdomain: external_exports.string().trim().max(60).optional().transform((value) => value ? value.toLowerCase() : null).superRefine((value, ctx) => {
|
|
14727
|
+
if (value === null) return;
|
|
14728
|
+
const problem = subdomainProblem(value);
|
|
14729
|
+
if (problem === "invalid") {
|
|
14730
|
+
ctx.addIssue({
|
|
14731
|
+
code: external_exports.ZodIssueCode.custom,
|
|
14732
|
+
message: "Use lowercase letters, numbers, and single hyphens (up to 54 characters)."
|
|
14733
|
+
});
|
|
14734
|
+
} else if (problem === "reserved") {
|
|
14735
|
+
ctx.addIssue({
|
|
14736
|
+
code: external_exports.ZodIssueCode.custom,
|
|
14737
|
+
message: "This subdomain is reserved."
|
|
14738
|
+
});
|
|
14739
|
+
}
|
|
14740
|
+
})
|
|
14675
14741
|
});
|
|
14676
14742
|
|
|
14677
14743
|
// ../../packages/build/src/package-manager.ts
|
|
@@ -14722,10 +14788,46 @@ async function detectPackageManager(root) {
|
|
|
14722
14788
|
);
|
|
14723
14789
|
}
|
|
14724
14790
|
|
|
14791
|
+
// ../../packages/build/src/proxy-to-middleware.ts
|
|
14792
|
+
import { access as access2, readFile as readFile3, rename, writeFile as writeFile2 } from "fs/promises";
|
|
14793
|
+
import { join as join3 } from "path";
|
|
14794
|
+
var EXTENSIONS = ["ts", "tsx", "js", "jsx"];
|
|
14795
|
+
var DIRECTORIES = ["", "src"];
|
|
14796
|
+
async function exists2(path) {
|
|
14797
|
+
try {
|
|
14798
|
+
await access2(path);
|
|
14799
|
+
return true;
|
|
14800
|
+
} catch {
|
|
14801
|
+
return false;
|
|
14802
|
+
}
|
|
14803
|
+
}
|
|
14804
|
+
function renameExport(source) {
|
|
14805
|
+
return source.replace(
|
|
14806
|
+
/(export\s+(?:default\s+)?(?:async\s+)?function\s+)proxy\b/g,
|
|
14807
|
+
"$1middleware"
|
|
14808
|
+
).replace(/(export\s+const\s+)proxy\b/g, "$1middleware");
|
|
14809
|
+
}
|
|
14810
|
+
async function convertProxyToMiddleware(appRoot) {
|
|
14811
|
+
for (const dir of DIRECTORIES) {
|
|
14812
|
+
for (const ext of EXTENSIONS) {
|
|
14813
|
+
const rel = join3(dir, `proxy.${ext}`);
|
|
14814
|
+
const proxyPath = join3(appRoot, rel);
|
|
14815
|
+
if (!await exists2(proxyPath)) continue;
|
|
14816
|
+
const middlewarePath = join3(appRoot, dir, `middleware.${ext}`);
|
|
14817
|
+
if (await exists2(middlewarePath)) return { converted: false };
|
|
14818
|
+
const source = await readFile3(proxyPath, "utf8");
|
|
14819
|
+
await writeFile2(middlewarePath, renameExport(source));
|
|
14820
|
+
await rename(proxyPath, `${proxyPath}.converted`);
|
|
14821
|
+
return { converted: true, file: rel };
|
|
14822
|
+
}
|
|
14823
|
+
}
|
|
14824
|
+
return { converted: false };
|
|
14825
|
+
}
|
|
14826
|
+
|
|
14725
14827
|
// ../../packages/build/src/platform-config.ts
|
|
14726
|
-
import { access as
|
|
14828
|
+
import { access as access3, writeFile as writeFile3 } from "fs/promises";
|
|
14727
14829
|
import { createRequire } from "module";
|
|
14728
|
-
import { join as
|
|
14830
|
+
import { join as join4 } from "path";
|
|
14729
14831
|
var COMPATIBILITY_DATE = "2026-08-19";
|
|
14730
14832
|
var NEXT_CONFIG_FILES = [
|
|
14731
14833
|
"next.config.js",
|
|
@@ -14735,31 +14837,31 @@ var NEXT_CONFIG_FILES = [
|
|
|
14735
14837
|
];
|
|
14736
14838
|
async function pathExists(path) {
|
|
14737
14839
|
try {
|
|
14738
|
-
await
|
|
14840
|
+
await access3(path);
|
|
14739
14841
|
return true;
|
|
14740
14842
|
} catch {
|
|
14741
14843
|
return false;
|
|
14742
14844
|
}
|
|
14743
14845
|
}
|
|
14744
14846
|
async function createPlatformBuildConfig(appRoot, deploymentId, writer = async (path, contents) => {
|
|
14745
|
-
await
|
|
14847
|
+
await writeFile3(path, contents, "utf8");
|
|
14746
14848
|
}, cloudflareModulePath = createRequire(import.meta.url).resolve(
|
|
14747
14849
|
"@opennextjs/cloudflare"
|
|
14748
|
-
),
|
|
14749
|
-
const openNextConfigPath =
|
|
14750
|
-
const wranglerConfigPath =
|
|
14751
|
-
const packageManagerConfigPath =
|
|
14850
|
+
), exists3 = pathExists) {
|
|
14851
|
+
const openNextConfigPath = join4(appRoot, ".next-deploy-open-next.config.mjs");
|
|
14852
|
+
const wranglerConfigPath = join4(appRoot, ".next-deploy-wrangler.json");
|
|
14853
|
+
const packageManagerConfigPath = join4(appRoot, ".next-deploy-user.npmrc");
|
|
14752
14854
|
const safeDeploymentId = deploymentId.replace(/[^a-z0-9-]/gi, "-");
|
|
14753
14855
|
let hasNextConfig = false;
|
|
14754
14856
|
for (const name of NEXT_CONFIG_FILES) {
|
|
14755
|
-
if (await
|
|
14857
|
+
if (await exists3(join4(appRoot, name))) {
|
|
14756
14858
|
hasNextConfig = true;
|
|
14757
14859
|
break;
|
|
14758
14860
|
}
|
|
14759
14861
|
}
|
|
14760
14862
|
if (!hasNextConfig) {
|
|
14761
14863
|
await writer(
|
|
14762
|
-
|
|
14864
|
+
join4(appRoot, "next.config.mjs"),
|
|
14763
14865
|
'export default { output: "standalone" };\n'
|
|
14764
14866
|
);
|
|
14765
14867
|
}
|
|
@@ -14800,8 +14902,8 @@ export default defineCloudflareConfig({});
|
|
|
14800
14902
|
}
|
|
14801
14903
|
|
|
14802
14904
|
// ../../packages/build/src/open-next.ts
|
|
14803
|
-
import { access as
|
|
14804
|
-
import { extname, isAbsolute, join as
|
|
14905
|
+
import { access as access4, readdir, readFile as readFile4 } from "fs/promises";
|
|
14906
|
+
import { extname, isAbsolute, join as join5, relative, resolve, sep } from "path";
|
|
14805
14907
|
function parseJsonc(source) {
|
|
14806
14908
|
let output = "";
|
|
14807
14909
|
let index = 0;
|
|
@@ -14896,7 +14998,7 @@ async function listFiles(root) {
|
|
|
14896
14998
|
for (const entry of entries.sort(
|
|
14897
14999
|
(left, right) => left.name.localeCompare(right.name)
|
|
14898
15000
|
)) {
|
|
14899
|
-
const path =
|
|
15001
|
+
const path = join5(directory, entry.name);
|
|
14900
15002
|
if (entry.isSymbolicLink()) {
|
|
14901
15003
|
throw new DeploymentError(
|
|
14902
15004
|
"ARTIFACT_INVALID",
|
|
@@ -14907,7 +15009,7 @@ async function listFiles(root) {
|
|
|
14907
15009
|
else if (entry.isFile()) {
|
|
14908
15010
|
files.push({
|
|
14909
15011
|
name: relative(root, path).split(sep).join("/"),
|
|
14910
|
-
data: await
|
|
15012
|
+
data: await readFile4(path),
|
|
14911
15013
|
contentType: contentType(path)
|
|
14912
15014
|
});
|
|
14913
15015
|
}
|
|
@@ -14926,13 +15028,13 @@ async function findWranglerConfig(root, configuredPath) {
|
|
|
14926
15028
|
"Wrangler config escapes the application root."
|
|
14927
15029
|
);
|
|
14928
15030
|
}
|
|
14929
|
-
await
|
|
15031
|
+
await access4(resolved);
|
|
14930
15032
|
return resolved;
|
|
14931
15033
|
}
|
|
14932
15034
|
for (const name of ["wrangler.jsonc", "wrangler.json"]) {
|
|
14933
|
-
const path =
|
|
15035
|
+
const path = join5(root, name);
|
|
14934
15036
|
try {
|
|
14935
|
-
await
|
|
15037
|
+
await access4(path);
|
|
14936
15038
|
return path;
|
|
14937
15039
|
} catch {
|
|
14938
15040
|
}
|
|
@@ -14946,7 +15048,7 @@ async function readOpenNextArtifact(appRoot, identity, wranglerConfigPath) {
|
|
|
14946
15048
|
try {
|
|
14947
15049
|
const configPath = await findWranglerConfig(appRoot, wranglerConfigPath);
|
|
14948
15050
|
const metadata = parseJsonc(
|
|
14949
|
-
await
|
|
15051
|
+
await readFile4(configPath, "utf8")
|
|
14950
15052
|
);
|
|
14951
15053
|
if (typeof metadata.main !== "string" || typeof metadata.compatibility_date !== "string") {
|
|
14952
15054
|
throw new DeploymentError(
|
|
@@ -14967,8 +15069,8 @@ async function readOpenNextArtifact(appRoot, identity, wranglerConfigPath) {
|
|
|
14967
15069
|
"Worker entrypoint must be inside .open-next."
|
|
14968
15070
|
);
|
|
14969
15071
|
}
|
|
14970
|
-
await
|
|
14971
|
-
const configuredAssets = typeof metadata.assets?.directory === "string" ? confinedPath(appRoot, metadata.assets.directory, "Assets directory") :
|
|
15072
|
+
await access4(entrypointPath);
|
|
15073
|
+
const configuredAssets = typeof metadata.assets?.directory === "string" ? confinedPath(appRoot, metadata.assets.directory, "Assets directory") : join5(outputRoot, "assets");
|
|
14972
15074
|
const assetsRelation = relative(outputRoot, configuredAssets);
|
|
14973
15075
|
if (assetsRelation === ".." || assetsRelation.startsWith(`..${sep}`) || isAbsolute(assetsRelation)) {
|
|
14974
15076
|
throw new DeploymentError(
|
|
@@ -14976,10 +15078,10 @@ async function readOpenNextArtifact(appRoot, identity, wranglerConfigPath) {
|
|
|
14976
15078
|
"Assets directory must be inside .open-next."
|
|
14977
15079
|
);
|
|
14978
15080
|
}
|
|
14979
|
-
const bundleRoot =
|
|
15081
|
+
const bundleRoot = join5(outputRoot, "worker-bundle");
|
|
14980
15082
|
let bundleFiles = null;
|
|
14981
15083
|
try {
|
|
14982
|
-
await
|
|
15084
|
+
await access4(bundleRoot);
|
|
14983
15085
|
bundleFiles = await listFiles(bundleRoot);
|
|
14984
15086
|
} catch {
|
|
14985
15087
|
}
|
|
@@ -15162,13 +15264,13 @@ function resolveAppRoot(checkout, configuredRoot) {
|
|
|
15162
15264
|
}
|
|
15163
15265
|
|
|
15164
15266
|
// ../../packages/build/src/next-project.ts
|
|
15165
|
-
import { readFile as
|
|
15166
|
-
import { join as
|
|
15267
|
+
import { readFile as readFile5 } from "fs/promises";
|
|
15268
|
+
import { join as join6 } from "path";
|
|
15167
15269
|
async function validateNextProject(root) {
|
|
15168
15270
|
let packageJson;
|
|
15169
15271
|
try {
|
|
15170
15272
|
packageJson = JSON.parse(
|
|
15171
|
-
await
|
|
15273
|
+
await readFile5(join6(root, "package.json"), "utf8")
|
|
15172
15274
|
);
|
|
15173
15275
|
} catch (error51) {
|
|
15174
15276
|
throw new DeploymentError(
|
|
@@ -15197,7 +15299,7 @@ async function validateNextProject(root) {
|
|
|
15197
15299
|
|
|
15198
15300
|
// ../../packages/build/src/local-build-executor.ts
|
|
15199
15301
|
var defaultDependencies = {
|
|
15200
|
-
createWorkspace: () => mkdtemp(
|
|
15302
|
+
createWorkspace: () => mkdtemp(join7(tmpdir(), "next-deploy-build-")),
|
|
15201
15303
|
removeWorkspace: (path) => rm(path, { recursive: true, force: true }),
|
|
15202
15304
|
runCommand,
|
|
15203
15305
|
detectPackageManager,
|
|
@@ -15207,7 +15309,8 @@ var defaultDependencies = {
|
|
|
15207
15309
|
readOpenNextArtifact,
|
|
15208
15310
|
openNextCommand: "opennextjs-cloudflare",
|
|
15209
15311
|
wranglerCommand: "wrangler",
|
|
15210
|
-
cacheFetch: (input, init) => fetch(input, init)
|
|
15312
|
+
cacheFetch: (input, init) => fetch(input, init),
|
|
15313
|
+
convertProxyToMiddleware
|
|
15211
15314
|
};
|
|
15212
15315
|
function sanitizeCacheKey(value) {
|
|
15213
15316
|
return value.replace(/[^A-Za-z0-9._-]/g, "-").slice(0, 128);
|
|
@@ -15247,14 +15350,14 @@ var LocalBuildExecutor = class {
|
|
|
15247
15350
|
}
|
|
15248
15351
|
async build(input, observer, cache) {
|
|
15249
15352
|
const workspace = await this.dependencies.createWorkspace();
|
|
15250
|
-
const checkout =
|
|
15251
|
-
const pmCacheDir =
|
|
15353
|
+
const checkout = join7(workspace, "checkout");
|
|
15354
|
+
const pmCacheDir = join7(workspace, ".pm-store");
|
|
15252
15355
|
let cacheSeq = 0;
|
|
15253
15356
|
const cachePorts = cache ? {
|
|
15254
15357
|
transport: cache,
|
|
15255
15358
|
fetch: this.dependencies.cacheFetch ?? ((url2, init) => fetch(url2, init)),
|
|
15256
15359
|
runCommand: this.dependencies.runCommand,
|
|
15257
|
-
tmpFile: (suffix) =>
|
|
15360
|
+
tmpFile: (suffix) => join7(workspace, `cache-${String(cacheSeq++)}${suffix}`)
|
|
15258
15361
|
} : null;
|
|
15259
15362
|
try {
|
|
15260
15363
|
await notifyStatus(observer, "CLONING");
|
|
@@ -15297,7 +15400,22 @@ var LocalBuildExecutor = class {
|
|
|
15297
15400
|
"Git returned an invalid commit SHA."
|
|
15298
15401
|
);
|
|
15299
15402
|
}
|
|
15300
|
-
await
|
|
15403
|
+
const subject = await this.dependencies.runCommand(
|
|
15404
|
+
{
|
|
15405
|
+
command: "git",
|
|
15406
|
+
args: ["log", "-1", "--format=%s"],
|
|
15407
|
+
cwd: checkout,
|
|
15408
|
+
timeoutMs: 1e4,
|
|
15409
|
+
stage: "CLONING",
|
|
15410
|
+
errorCode: "CLONE_FAILED"
|
|
15411
|
+
},
|
|
15412
|
+
observer
|
|
15413
|
+
);
|
|
15414
|
+
const gitCommitMessage = [...subject.stdout.at(-1)?.trim() ?? ""].slice(0, 300).join("");
|
|
15415
|
+
await observer.onMetadata?.({
|
|
15416
|
+
gitCommitSha,
|
|
15417
|
+
...gitCommitMessage ? { gitCommitMessage } : {}
|
|
15418
|
+
});
|
|
15301
15419
|
const appRoot = this.dependencies.resolveAppRoot(
|
|
15302
15420
|
checkout,
|
|
15303
15421
|
input.rootDirectory
|
|
@@ -15308,6 +15426,14 @@ var LocalBuildExecutor = class {
|
|
|
15308
15426
|
"CLONING",
|
|
15309
15427
|
`Validated Next.js ${project.nextVersion}`
|
|
15310
15428
|
);
|
|
15429
|
+
const conversion = await (this.dependencies.convertProxyToMiddleware ?? convertProxyToMiddleware)(appRoot);
|
|
15430
|
+
if (conversion.converted) {
|
|
15431
|
+
await observer.onLog({
|
|
15432
|
+
level: "WARN",
|
|
15433
|
+
stage: "CLONING",
|
|
15434
|
+
message: `Converted ${conversion.file ?? "proxy"} to edge middleware. Next.js 16 proxy runs on the Node.js runtime, which Cloudflare does not support; middleware runs on the Edge runtime, so Node.js-only APIs are unavailable.`
|
|
15435
|
+
});
|
|
15436
|
+
}
|
|
15311
15437
|
const platformConfig = await this.dependencies.createPlatformBuildConfig(
|
|
15312
15438
|
appRoot,
|
|
15313
15439
|
input.deploymentId
|
|
@@ -15355,7 +15481,7 @@ var LocalBuildExecutor = class {
|
|
|
15355
15481
|
observer
|
|
15356
15482
|
);
|
|
15357
15483
|
await notifyStatus(observer, "BUILDING");
|
|
15358
|
-
const nextCacheDir =
|
|
15484
|
+
const nextCacheDir = join7(appRoot, ".next", "cache");
|
|
15359
15485
|
const nextKey = sanitizeCacheKey(input.branch);
|
|
15360
15486
|
if (cachePorts) {
|
|
15361
15487
|
await tryRestore("next", nextKey, nextCacheDir, cachePorts, observer);
|
|
@@ -15407,7 +15533,7 @@ var LocalBuildExecutor = class {
|
|
|
15407
15533
|
],
|
|
15408
15534
|
cwd: appRoot,
|
|
15409
15535
|
env: {
|
|
15410
|
-
WRANGLER_LOG_PATH:
|
|
15536
|
+
WRANGLER_LOG_PATH: join7(appRoot, ".open-next", "wrangler.log")
|
|
15411
15537
|
},
|
|
15412
15538
|
timeoutMs: 5 * 6e4,
|
|
15413
15539
|
stage: "BUILDING",
|
|
@@ -15437,15 +15563,53 @@ var LocalBuildExecutor = class {
|
|
|
15437
15563
|
}
|
|
15438
15564
|
};
|
|
15439
15565
|
|
|
15566
|
+
// src/git-info.ts
|
|
15567
|
+
import { execFile } from "child_process";
|
|
15568
|
+
var SUPPORTED_REMOTE = [
|
|
15569
|
+
/^https:\/\/[^\s]+$/,
|
|
15570
|
+
/^ssh:\/\/[^\s]+$/,
|
|
15571
|
+
/^git@[A-Za-z0-9.-]+:[A-Za-z0-9._/-]+(\.git)?$/
|
|
15572
|
+
];
|
|
15573
|
+
var defaultExec = (args, cwd) => new Promise((resolve3, reject) => {
|
|
15574
|
+
execFile("git", args, { cwd }, (error51, stdout) => {
|
|
15575
|
+
if (error51) reject(error51);
|
|
15576
|
+
else resolve3(stdout);
|
|
15577
|
+
});
|
|
15578
|
+
});
|
|
15579
|
+
async function tryExec(exec, args, cwd) {
|
|
15580
|
+
try {
|
|
15581
|
+
const out = (await exec(args, cwd)).trim();
|
|
15582
|
+
return out.length > 0 ? out : null;
|
|
15583
|
+
} catch {
|
|
15584
|
+
return null;
|
|
15585
|
+
}
|
|
15586
|
+
}
|
|
15587
|
+
async function detectGitInfo(dir, exec = defaultExec) {
|
|
15588
|
+
const remote = await tryExec(exec, ["remote", "get-url", "origin"], dir);
|
|
15589
|
+
const branch = await tryExec(
|
|
15590
|
+
exec,
|
|
15591
|
+
["rev-parse", "--abbrev-ref", "HEAD"],
|
|
15592
|
+
dir
|
|
15593
|
+
);
|
|
15594
|
+
return {
|
|
15595
|
+
repositoryUrl: remote !== null && SUPPORTED_REMOTE.some((re) => re.test(remote)) ? remote : null,
|
|
15596
|
+
branch: branch !== null && branch !== "HEAD" ? branch : null
|
|
15597
|
+
};
|
|
15598
|
+
}
|
|
15599
|
+
|
|
15600
|
+
// src/login.ts
|
|
15601
|
+
import { spawn as spawn2 } from "child_process";
|
|
15602
|
+
import { homedir as homedir2 } from "os";
|
|
15603
|
+
|
|
15440
15604
|
// src/session.ts
|
|
15441
15605
|
import { mkdirSync, readFileSync, rmSync, writeFileSync } from "fs";
|
|
15442
15606
|
import { homedir } from "os";
|
|
15443
|
-
import { join as
|
|
15607
|
+
import { join as join8 } from "path";
|
|
15444
15608
|
function credentialsDir(home = homedir()) {
|
|
15445
|
-
return
|
|
15609
|
+
return join8(home, ".naro");
|
|
15446
15610
|
}
|
|
15447
15611
|
function credentialsFile(home = homedir()) {
|
|
15448
|
-
return
|
|
15612
|
+
return join8(credentialsDir(home), "credentials.json");
|
|
15449
15613
|
}
|
|
15450
15614
|
function saveSession(session, home = homedir()) {
|
|
15451
15615
|
mkdirSync(credentialsDir(home), { recursive: true, mode: 448 });
|
|
@@ -15610,6 +15774,71 @@ async function login(deps) {
|
|
|
15610
15774
|
}
|
|
15611
15775
|
}
|
|
15612
15776
|
|
|
15777
|
+
// src/login.ts
|
|
15778
|
+
var stdio = {
|
|
15779
|
+
out: (m) => process.stdout.write(`${m}
|
|
15780
|
+
`),
|
|
15781
|
+
err: (m) => process.stderr.write(`${m}
|
|
15782
|
+
`)
|
|
15783
|
+
};
|
|
15784
|
+
function openBrowser(url2) {
|
|
15785
|
+
const platform = process.platform;
|
|
15786
|
+
const command = platform === "darwin" ? "open" : platform === "win32" ? "cmd" : "xdg-open";
|
|
15787
|
+
const args = platform === "win32" ? ["/c", "start", "", url2] : [url2];
|
|
15788
|
+
spawn2(command, args, { stdio: "ignore", detached: true }).unref();
|
|
15789
|
+
}
|
|
15790
|
+
async function runLogin(io = stdio) {
|
|
15791
|
+
io.out("Opening your browser to sign in with GitHub...");
|
|
15792
|
+
const session = await login({
|
|
15793
|
+
openBrowser: (url2) => {
|
|
15794
|
+
io.out(`If your browser did not open, visit:
|
|
15795
|
+
${url2}`);
|
|
15796
|
+
openBrowser(url2);
|
|
15797
|
+
}
|
|
15798
|
+
});
|
|
15799
|
+
saveSession(session);
|
|
15800
|
+
io.out(`\u2705 Logged in as ${session.user.email ?? session.user.id}`);
|
|
15801
|
+
}
|
|
15802
|
+
async function runWhoami(io = stdio, home = homedir2(), refresh = refreshStoredSession) {
|
|
15803
|
+
let session = loadStoredSession(home);
|
|
15804
|
+
if (!session) {
|
|
15805
|
+
io.err("Not logged in. Run `naro login`.");
|
|
15806
|
+
process.exitCode = 1;
|
|
15807
|
+
return;
|
|
15808
|
+
}
|
|
15809
|
+
if (isExpired(session)) {
|
|
15810
|
+
try {
|
|
15811
|
+
session = await refresh(session.refresh_token);
|
|
15812
|
+
saveSession(session, home);
|
|
15813
|
+
} catch {
|
|
15814
|
+
io.err("Session expired. Run `naro login`.");
|
|
15815
|
+
process.exitCode = 1;
|
|
15816
|
+
return;
|
|
15817
|
+
}
|
|
15818
|
+
}
|
|
15819
|
+
const handle = session.user.github ? ` (${session.user.github})` : "";
|
|
15820
|
+
io.out(`Logged in as ${session.user.email ?? session.user.id}${handle}`);
|
|
15821
|
+
}
|
|
15822
|
+
async function defaultSignOut(session) {
|
|
15823
|
+
const client = createAuthClient();
|
|
15824
|
+
await client.auth.setSession({
|
|
15825
|
+
access_token: session.access_token,
|
|
15826
|
+
refresh_token: session.refresh_token
|
|
15827
|
+
});
|
|
15828
|
+
await client.auth.signOut();
|
|
15829
|
+
}
|
|
15830
|
+
async function runLogout(io = stdio, home = homedir2(), signOut = defaultSignOut) {
|
|
15831
|
+
const session = loadStoredSession(home);
|
|
15832
|
+
if (session) {
|
|
15833
|
+
try {
|
|
15834
|
+
await signOut(session);
|
|
15835
|
+
} catch {
|
|
15836
|
+
}
|
|
15837
|
+
}
|
|
15838
|
+
clearSession(home);
|
|
15839
|
+
io.out("Logged out.");
|
|
15840
|
+
}
|
|
15841
|
+
|
|
15613
15842
|
// src/upload.ts
|
|
15614
15843
|
function base(opts) {
|
|
15615
15844
|
return `${opts.controlPlaneUrl.replace(/\/$/, "")}/api/internal/deployments/${opts.deploymentId}`;
|
|
@@ -15643,7 +15872,10 @@ function manifest(artifact) {
|
|
|
15643
15872
|
projectId: artifact.projectId,
|
|
15644
15873
|
entrypoint: artifact.entrypoint.name,
|
|
15645
15874
|
modules: [artifact.entrypoint, ...artifact.modules].map(meta3),
|
|
15646
|
-
assets: artifact.assets.map(
|
|
15875
|
+
assets: artifact.assets.map((file2) => ({
|
|
15876
|
+
...meta3(file2),
|
|
15877
|
+
hash: hashAsset(file2.data)
|
|
15878
|
+
})),
|
|
15647
15879
|
compatibilityDate: artifact.compatibilityDate,
|
|
15648
15880
|
compatibilityFlags: artifact.compatibilityFlags,
|
|
15649
15881
|
assetsBinding: artifact.assetsBinding
|
|
@@ -15678,7 +15910,18 @@ async function startCliDeployment(accessToken, opts) {
|
|
|
15678
15910
|
"Content-Type": "application/json",
|
|
15679
15911
|
Authorization: `Bearer ${accessToken}`
|
|
15680
15912
|
},
|
|
15681
|
-
body: JSON.stringify({
|
|
15913
|
+
body: JSON.stringify({
|
|
15914
|
+
name: opts.name,
|
|
15915
|
+
production: opts.production,
|
|
15916
|
+
...opts.repositoryUrl != null && {
|
|
15917
|
+
repositoryUrl: opts.repositoryUrl
|
|
15918
|
+
},
|
|
15919
|
+
...opts.branch != null && { branch: opts.branch },
|
|
15920
|
+
...opts.rootDirectory != null && {
|
|
15921
|
+
rootDirectory: opts.rootDirectory
|
|
15922
|
+
},
|
|
15923
|
+
...opts.env !== void 0 && { env: opts.env }
|
|
15924
|
+
})
|
|
15682
15925
|
}
|
|
15683
15926
|
);
|
|
15684
15927
|
if (!response.ok) {
|
|
@@ -15693,13 +15936,26 @@ async function startCliDeployment(accessToken, opts) {
|
|
|
15693
15936
|
function controlPlaneUrl(env = process.env) {
|
|
15694
15937
|
return (env.NARO_CONTROL_PLANE_URL ?? "https://naro.sh").replace(/\/$/, "");
|
|
15695
15938
|
}
|
|
15696
|
-
async function
|
|
15697
|
-
|
|
15698
|
-
|
|
15699
|
-
|
|
15700
|
-
|
|
15701
|
-
|
|
15939
|
+
async function requireSessionOrLogin(log2, home = homedir3(), loginFlow = () => login({
|
|
15940
|
+
openBrowser: (url2) => {
|
|
15941
|
+
log2(`If your browser did not open, visit:
|
|
15942
|
+
${url2}`);
|
|
15943
|
+
openBrowser(url2);
|
|
15944
|
+
}
|
|
15945
|
+
})) {
|
|
15946
|
+
const stored = loadStoredSession(home);
|
|
15947
|
+
if (stored) {
|
|
15948
|
+
if (!isExpired(stored)) return stored;
|
|
15949
|
+
try {
|
|
15950
|
+
const refreshed = await refreshStoredSession(stored.refresh_token);
|
|
15951
|
+
saveSession(refreshed, home);
|
|
15952
|
+
return refreshed;
|
|
15953
|
+
} catch {
|
|
15954
|
+
}
|
|
15702
15955
|
}
|
|
15956
|
+
log2("Not logged in \u2014 opening your browser to sign in with GitHub\u2026");
|
|
15957
|
+
const session = await loginFlow();
|
|
15958
|
+
saveSession(session, home);
|
|
15703
15959
|
return session;
|
|
15704
15960
|
}
|
|
15705
15961
|
function eventsObserver(cp2, deploymentId, token, fetchImpl = fetch) {
|
|
@@ -15737,7 +15993,7 @@ function parseDotenv(text) {
|
|
|
15737
15993
|
}
|
|
15738
15994
|
function readProjectEnv(dir) {
|
|
15739
15995
|
for (const name of [".env.local", ".env.production", ".env"]) {
|
|
15740
|
-
const path =
|
|
15996
|
+
const path = join9(dir, name);
|
|
15741
15997
|
if (existsSync(path)) return parseDotenv(readFileSync2(path, "utf8"));
|
|
15742
15998
|
}
|
|
15743
15999
|
return {};
|
|
@@ -15749,7 +16005,7 @@ function slugify2(value) {
|
|
|
15749
16005
|
async function projectName(sourceDir) {
|
|
15750
16006
|
try {
|
|
15751
16007
|
const pkg = JSON.parse(
|
|
15752
|
-
await
|
|
16008
|
+
await readFile6(join9(sourceDir, "package.json"), "utf8")
|
|
15753
16009
|
);
|
|
15754
16010
|
if (pkg.name) return pkg.name;
|
|
15755
16011
|
} catch {
|
|
@@ -15760,7 +16016,7 @@ var COPY_SKIP = /(^|[\\/])(node_modules|\.next|\.open-next|\.git|\.wrangler|\.tu
|
|
|
15760
16016
|
function resolveBin(name) {
|
|
15761
16017
|
let dir = dirname(fileURLToPath(import.meta.url));
|
|
15762
16018
|
for (; ; ) {
|
|
15763
|
-
const candidate =
|
|
16019
|
+
const candidate = join9(dir, "node_modules", ".bin", name);
|
|
15764
16020
|
if (existsSync(candidate)) return candidate;
|
|
15765
16021
|
const parent = dirname(dir);
|
|
15766
16022
|
if (parent === dir) return name;
|
|
@@ -15785,7 +16041,7 @@ async function detectPackageManagerLenient(root) {
|
|
|
15785
16041
|
}
|
|
15786
16042
|
function localDependencies(sourceDir) {
|
|
15787
16043
|
return {
|
|
15788
|
-
createWorkspace: () => mkdtemp2(
|
|
16044
|
+
createWorkspace: () => mkdtemp2(join9(tmpdir2(), "naro-build-")),
|
|
15789
16045
|
removeWorkspace: (path) => rm2(path, { recursive: true, force: true }),
|
|
15790
16046
|
async runCommand(spec, observer) {
|
|
15791
16047
|
if (spec.command === "git" && spec.args[0] === "clone") {
|
|
@@ -15800,6 +16056,9 @@ function localDependencies(sourceDir) {
|
|
|
15800
16056
|
if (spec.command === "git" && spec.args[0] === "rev-parse") {
|
|
15801
16057
|
return { stdout: ["0".repeat(40)], stderr: [] };
|
|
15802
16058
|
}
|
|
16059
|
+
if (spec.command === "git" && spec.args[0] === "log") {
|
|
16060
|
+
return { stdout: [], stderr: [] };
|
|
16061
|
+
}
|
|
15803
16062
|
return runCommand(spec, observer);
|
|
15804
16063
|
},
|
|
15805
16064
|
detectPackageManager: detectPackageManagerLenient,
|
|
@@ -15813,15 +16072,26 @@ function localDependencies(sourceDir) {
|
|
|
15813
16072
|
}
|
|
15814
16073
|
async function deployDirectory(sourceDir, options, log2) {
|
|
15815
16074
|
const cp2 = controlPlaneUrl();
|
|
15816
|
-
const session = await
|
|
16075
|
+
const session = await requireSessionOrLogin(log2);
|
|
15817
16076
|
const name = slugify2(options.name ?? await projectName(sourceDir));
|
|
15818
16077
|
const production = options.production ?? false;
|
|
16078
|
+
const git = await detectGitInfo(sourceDir);
|
|
16079
|
+
const branch = options.branch ?? git.branch;
|
|
16080
|
+
if (git.repositoryUrl) log2(`\u25B8 linking ${git.repositoryUrl}`);
|
|
16081
|
+
if (options.env && Object.keys(options.env).length > 0)
|
|
16082
|
+
log2(`\u25B8 syncing ${Object.keys(options.env).length} env var(s)`);
|
|
15819
16083
|
log2("\u25B8 starting deployment");
|
|
15820
16084
|
const ctx = await startCliDeployment(session.access_token, {
|
|
15821
16085
|
name,
|
|
15822
16086
|
production,
|
|
15823
|
-
controlPlaneUrl: cp2
|
|
16087
|
+
controlPlaneUrl: cp2,
|
|
16088
|
+
repositoryUrl: git.repositoryUrl,
|
|
16089
|
+
branch,
|
|
16090
|
+
rootDirectory: options.rootDirectory,
|
|
16091
|
+
env: options.env
|
|
15824
16092
|
});
|
|
16093
|
+
if (ctx.envSkipped?.length)
|
|
16094
|
+
log2(`\u26A0 skipped env: ${ctx.envSkipped.join(", ")}`);
|
|
15825
16095
|
const executor = new LocalBuildExecutor(localDependencies(sourceDir));
|
|
15826
16096
|
const observer = eventsObserver(cp2, ctx.deploymentId, ctx.callbackToken);
|
|
15827
16097
|
const result = await executor.build(
|
|
@@ -15840,22 +16110,20 @@ async function deployDirectory(sourceDir, options, log2) {
|
|
|
15840
16110
|
deploymentId: ctx.deploymentId,
|
|
15841
16111
|
callbackToken: ctx.callbackToken
|
|
15842
16112
|
});
|
|
16113
|
+
const surface = ctx.subdomain ?? name;
|
|
15843
16114
|
return {
|
|
15844
|
-
workerName:
|
|
15845
|
-
url: uploaded.previewUrl ?? `${
|
|
16115
|
+
workerName: surface,
|
|
16116
|
+
url: uploaded.previewUrl ?? `${surface}${production ? "" : "-preview"}.naro.sh`
|
|
15846
16117
|
};
|
|
15847
16118
|
}
|
|
15848
16119
|
|
|
15849
16120
|
export {
|
|
15850
|
-
|
|
15851
|
-
|
|
15852
|
-
|
|
15853
|
-
isExpired,
|
|
15854
|
-
createAuthClient,
|
|
15855
|
-
refreshStoredSession,
|
|
15856
|
-
login,
|
|
16121
|
+
runLogin,
|
|
16122
|
+
runWhoami,
|
|
16123
|
+
runLogout,
|
|
15857
16124
|
startCliDeployment,
|
|
15858
16125
|
controlPlaneUrl,
|
|
16126
|
+
requireSessionOrLogin,
|
|
15859
16127
|
eventsObserver,
|
|
15860
16128
|
parseDotenv,
|
|
15861
16129
|
readProjectEnv,
|
package/dist/deploy.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { BuildObserver } from "./artifact-types";
|
|
2
|
+
import { type StoredSession } from "./session";
|
|
2
3
|
export interface CliDeploymentContext {
|
|
3
4
|
deploymentId: string;
|
|
4
5
|
projectId: string;
|
|
@@ -7,14 +8,21 @@ export interface CliDeploymentContext {
|
|
|
7
8
|
rootDirectory: string | null;
|
|
8
9
|
env: Record<string, string>;
|
|
9
10
|
controlPlaneUrl: string;
|
|
11
|
+
envSkipped?: string[];
|
|
12
|
+
subdomain?: string;
|
|
10
13
|
}
|
|
11
14
|
export declare function startCliDeployment(accessToken: string, opts: {
|
|
12
15
|
name: string;
|
|
13
16
|
production: boolean;
|
|
14
17
|
controlPlaneUrl: string;
|
|
18
|
+
repositoryUrl?: string | null | undefined;
|
|
19
|
+
branch?: string | null | undefined;
|
|
20
|
+
rootDirectory?: string | null | undefined;
|
|
21
|
+
env?: Record<string, string> | undefined;
|
|
15
22
|
fetch?: typeof fetch;
|
|
16
23
|
}): Promise<CliDeploymentContext>;
|
|
17
24
|
export declare function controlPlaneUrl(env?: NodeJS.ProcessEnv): string;
|
|
25
|
+
export declare function requireSessionOrLogin(log: (message: string) => void, home?: string, loginFlow?: () => Promise<StoredSession>): Promise<StoredSession>;
|
|
18
26
|
export declare function eventsObserver(cp: string, deploymentId: string, token: string, fetchImpl?: typeof fetch): BuildObserver;
|
|
19
27
|
export declare function parseDotenv(text: string): Record<string, string>;
|
|
20
28
|
export declare function readProjectEnv(dir: string): Record<string, string>;
|
|
@@ -24,6 +32,7 @@ export interface DeployOptions {
|
|
|
24
32
|
rootDirectory?: string | null;
|
|
25
33
|
production?: boolean;
|
|
26
34
|
env?: Record<string, string> | undefined;
|
|
35
|
+
branch?: string | undefined;
|
|
27
36
|
}
|
|
28
37
|
export interface DeployResult {
|
|
29
38
|
workerName: string;
|
package/dist/deploy.js
CHANGED
|
@@ -5,15 +5,17 @@ import {
|
|
|
5
5
|
eventsObserver,
|
|
6
6
|
parseDotenv,
|
|
7
7
|
readProjectEnv,
|
|
8
|
+
requireSessionOrLogin,
|
|
8
9
|
slugify,
|
|
9
10
|
startCliDeployment
|
|
10
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-IC4R5EYE.js";
|
|
11
12
|
export {
|
|
12
13
|
controlPlaneUrl,
|
|
13
14
|
deployDirectory,
|
|
14
15
|
eventsObserver,
|
|
15
16
|
parseDotenv,
|
|
16
17
|
readProjectEnv,
|
|
18
|
+
requireSessionOrLogin,
|
|
17
19
|
slugify,
|
|
18
20
|
startCliDeployment
|
|
19
21
|
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export interface GitInfo {
|
|
2
|
+
repositoryUrl: string | null;
|
|
3
|
+
branch: string | null;
|
|
4
|
+
}
|
|
5
|
+
export type GitExec = (args: string[], cwd: string) => Promise<string>;
|
|
6
|
+
/** Reads local git metadata for the deploy: origin remote URL + current branch. */
|
|
7
|
+
export declare function detectGitInfo(dir: string, exec?: GitExec): Promise<GitInfo>;
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,82 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
-
clearSession,
|
|
4
|
-
createAuthClient,
|
|
5
3
|
deployDirectory,
|
|
6
|
-
isExpired,
|
|
7
|
-
loadStoredSession,
|
|
8
|
-
login,
|
|
9
4
|
readProjectEnv,
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
// src/login.ts
|
|
15
|
-
import { spawn } from "child_process";
|
|
16
|
-
import { homedir } from "os";
|
|
17
|
-
var stdio = {
|
|
18
|
-
out: (m) => process.stdout.write(`${m}
|
|
19
|
-
`),
|
|
20
|
-
err: (m) => process.stderr.write(`${m}
|
|
21
|
-
`)
|
|
22
|
-
};
|
|
23
|
-
function openBrowser(url) {
|
|
24
|
-
const platform = process.platform;
|
|
25
|
-
const command = platform === "darwin" ? "open" : platform === "win32" ? "cmd" : "xdg-open";
|
|
26
|
-
const args = platform === "win32" ? ["/c", "start", "", url] : [url];
|
|
27
|
-
spawn(command, args, { stdio: "ignore", detached: true }).unref();
|
|
28
|
-
}
|
|
29
|
-
async function runLogin(io = stdio) {
|
|
30
|
-
io.out("Opening your browser to sign in with GitHub...");
|
|
31
|
-
const session = await login({
|
|
32
|
-
openBrowser: (url) => {
|
|
33
|
-
io.out(`If your browser did not open, visit:
|
|
34
|
-
${url}`);
|
|
35
|
-
openBrowser(url);
|
|
36
|
-
}
|
|
37
|
-
});
|
|
38
|
-
saveSession(session);
|
|
39
|
-
io.out(`\u2705 Logged in as ${session.user.email ?? session.user.id}`);
|
|
40
|
-
}
|
|
41
|
-
async function runWhoami(io = stdio, home = homedir(), refresh = refreshStoredSession) {
|
|
42
|
-
let session = loadStoredSession(home);
|
|
43
|
-
if (!session) {
|
|
44
|
-
io.err("Not logged in. Run `naro login`.");
|
|
45
|
-
process.exitCode = 1;
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
48
|
-
if (isExpired(session)) {
|
|
49
|
-
try {
|
|
50
|
-
session = await refresh(session.refresh_token);
|
|
51
|
-
saveSession(session, home);
|
|
52
|
-
} catch {
|
|
53
|
-
io.err("Session expired. Run `naro login`.");
|
|
54
|
-
process.exitCode = 1;
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
const handle = session.user.github ? ` (${session.user.github})` : "";
|
|
59
|
-
io.out(`Logged in as ${session.user.email ?? session.user.id}${handle}`);
|
|
60
|
-
}
|
|
61
|
-
async function defaultSignOut(session) {
|
|
62
|
-
const client = createAuthClient();
|
|
63
|
-
await client.auth.setSession({
|
|
64
|
-
access_token: session.access_token,
|
|
65
|
-
refresh_token: session.refresh_token
|
|
66
|
-
});
|
|
67
|
-
await client.auth.signOut();
|
|
68
|
-
}
|
|
69
|
-
async function runLogout(io = stdio, home = homedir(), signOut = defaultSignOut) {
|
|
70
|
-
const session = loadStoredSession(home);
|
|
71
|
-
if (session) {
|
|
72
|
-
try {
|
|
73
|
-
await signOut(session);
|
|
74
|
-
} catch {
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
clearSession(home);
|
|
78
|
-
io.out("Logged out.");
|
|
79
|
-
}
|
|
5
|
+
runLogin,
|
|
6
|
+
runLogout,
|
|
7
|
+
runWhoami
|
|
8
|
+
} from "./chunk-IC4R5EYE.js";
|
|
80
9
|
|
|
81
10
|
// src/index.ts
|
|
82
11
|
function parseFlags(argv) {
|
|
@@ -86,6 +15,7 @@ function parseFlags(argv) {
|
|
|
86
15
|
if (arg === "--prod" || arg === "--production") flags.production = true;
|
|
87
16
|
else if (arg === "--name") flags.name = argv[++i];
|
|
88
17
|
else if (arg === "--root") flags.root = argv[++i];
|
|
18
|
+
else if (arg === "--branch") flags.branch = argv[++i];
|
|
89
19
|
}
|
|
90
20
|
return flags;
|
|
91
21
|
}
|
|
@@ -95,15 +25,17 @@ Usage:
|
|
|
95
25
|
naro login
|
|
96
26
|
naro whoami
|
|
97
27
|
naro logout
|
|
98
|
-
naro deploy [--name <name>] [--root <dir>] [--prod]
|
|
28
|
+
naro deploy [--name <name>] [--root <dir>] [--branch <name>] [--prod]
|
|
99
29
|
|
|
100
30
|
Options:
|
|
101
|
-
--name
|
|
102
|
-
--root
|
|
103
|
-
--
|
|
31
|
+
--name Override the deployment name (defaults to package.json name)
|
|
32
|
+
--root Sub-directory that contains the Next.js app (where package.json is)
|
|
33
|
+
--branch Override the detected git branch
|
|
34
|
+
--prod Publish to production ({name}.naro.sh) instead of preview
|
|
104
35
|
|
|
105
36
|
Credentials:
|
|
106
37
|
Run \`naro login\` to authenticate via GitHub.
|
|
38
|
+
\`naro deploy\` signs you in automatically (opens your browser) when needed.
|
|
107
39
|
Set NARO_CONTROL_PLANE_URL to use a custom control plane (defaults to https://naro.sh).
|
|
108
40
|
`;
|
|
109
41
|
async function main() {
|
|
@@ -134,6 +66,7 @@ ${HELP}`);
|
|
|
134
66
|
{
|
|
135
67
|
name: flags.name,
|
|
136
68
|
rootDirectory: flags.root ?? null,
|
|
69
|
+
branch: flags.branch,
|
|
137
70
|
production: flags.production,
|
|
138
71
|
env
|
|
139
72
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "naro-cli",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"naro": "./dist/index.js"
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
"typescript": "7.0.2",
|
|
30
30
|
"vitest": "3.2.7",
|
|
31
31
|
"@next-deploy/build": "0.1.0",
|
|
32
|
-
"@next-deploy/
|
|
33
|
-
"@next-deploy/
|
|
32
|
+
"@next-deploy/core": "0.1.0",
|
|
33
|
+
"@next-deploy/config": "0.1.0"
|
|
34
34
|
},
|
|
35
35
|
"scripts": {
|
|
36
36
|
"build": "tsup && pnpm build:types",
|