@nocobase/app-cli-distribution 0.0.0-stage → 0.1.0-beta.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.
@@ -0,0 +1,57 @@
1
+ export interface DownloadToken {
2
+ readonly token: string;
3
+ readonly expiresAt: string;
4
+ readonly maxDownloads: number;
5
+ }
6
+ export interface Clock {
7
+ now(): Date;
8
+ }
9
+ /** How long a download token stays usable. */
10
+ export declare const DOWNLOAD_TOKEN_TTL_MS: number;
11
+ /** How many tarball downloads one token allows, so a failed download can be retried. */
12
+ export declare const DOWNLOAD_TOKEN_MAX_DOWNLOADS = 3;
13
+ export interface DownloadTokenRecord {
14
+ readonly id: string;
15
+ readonly tokenHash: string;
16
+ readonly createdById: string | null;
17
+ readonly target: string | null;
18
+ readonly downloads: number;
19
+ readonly expiresAt: string;
20
+ readonly createdAt: string;
21
+ }
22
+ /** Storage operations within the host's transaction. Updates must compare the stored download count atomically. */
23
+ export interface DownloadTokenTransaction {
24
+ insert(record: DownloadTokenRecord): Promise<void>;
25
+ findByHash(hash: string): Promise<DownloadTokenRecord | null | undefined>;
26
+ updateIfDownloads(id: string, expected: number, values: {
27
+ target: string | null;
28
+ downloads: number;
29
+ }): Promise<boolean>;
30
+ }
31
+ export interface DownloadTokenStore {
32
+ transaction<T>(fn: (store: DownloadTokenTransaction) => Promise<T>): Promise<T>;
33
+ }
34
+ /** What a request with a download token asks for. */
35
+ export interface DownloadRequest {
36
+ readonly product?: string;
37
+ /** The platform it resolves or downloads for; absent for the manifest, and for the universal tarball. */
38
+ readonly target?: string;
39
+ /** A tarball download, which counts against the token. */
40
+ readonly download?: boolean;
41
+ }
42
+ export interface DownloadTokenService {
43
+ create(createdById: string | null): Promise<DownloadToken>;
44
+ /** Lets `request` through with `token`, binding its platform and counting a download; `DOWNLOAD_TOKEN_INVALID` otherwise. */
45
+ admit(token: string, request: DownloadRequest): Promise<void>;
46
+ }
47
+ export interface DownloadTokenServiceDeps {
48
+ /** The one product a download token downloads: the application's CLI (`agents.cli.name`). */
49
+ readonly product: string;
50
+ readonly store: DownloadTokenStore;
51
+ readonly ids: {
52
+ next(): string;
53
+ };
54
+ readonly clock: Clock;
55
+ }
56
+ export declare function createDownloadTokenService(deps: DownloadTokenServiceDeps): DownloadTokenService;
57
+ //# sourceMappingURL=download-tokens.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"download-tokens.d.ts","sourceRoot":"","sources":["../src/download-tokens.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;CAC/B;AACD,MAAM,WAAW,KAAK;IACpB,GAAG,IAAI,IAAI,CAAC;CACb;AACD,8CAA8C;AAC9C,eAAO,MAAM,qBAAqB,EAAE,MAAoB,CAAC;AAEzD,wFAAwF;AACxF,eAAO,MAAM,4BAA4B,IAAI,CAAC;AAE9C,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,mHAAmH;AACnH,MAAM,WAAW,wBAAwB;IACvC,MAAM,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnD,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;IAC1E,iBAAiB,CACf,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,GACnD,OAAO,CAAC,OAAO,CAAC,CAAC;CACrB;AACD,MAAM,WAAW,kBAAkB;IACjC,WAAW,CAAC,CAAC,EACX,EAAE,EAAE,CAAC,KAAK,EAAE,wBAAwB,KAAK,OAAO,CAAC,CAAC,CAAC,GAClD,OAAO,CAAC,CAAC,CAAC,CAAC;CACf;AAED,qDAAqD;AACrD,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,yGAAyG;IACzG,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,0DAA0D;IAC1D,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IAC3D,6HAA6H;IAC7H,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/D;AAED,MAAM,WAAW,wBAAwB;IACvC,6FAA6F;IAC7F,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,kBAAkB,CAAC;IACnC,QAAQ,CAAC,GAAG,EAAE;QAAE,IAAI,IAAI,MAAM,CAAA;KAAE,CAAC;IACjC,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;CACvB;AAED,wBAAgB,0BAA0B,CACxC,IAAI,EAAE,wBAAwB,GAC7B,oBAAoB,CAsEtB"}
@@ -0,0 +1,66 @@
1
+ import { ProtocolError } from '@nocobase/agent-protocol';
2
+ import { createHash, randomBytes } from 'node:crypto';
3
+ import { CREDENTIAL_PREFIXES } from '@nocobase/agent-protocol';
4
+ /** How long a download token stays usable. */
5
+ export const DOWNLOAD_TOKEN_TTL_MS = 30 * 60_000;
6
+ /** How many tarball downloads one token allows, so a failed download can be retried. */
7
+ export const DOWNLOAD_TOKEN_MAX_DOWNLOADS = 3;
8
+ export function createDownloadTokenService(deps) {
9
+ const { store, ids, clock, product } = deps;
10
+ const invalid = (message) => new ProtocolError('DOWNLOAD_TOKEN_INVALID', message);
11
+ const spent = () => invalid('The download token is unknown, expired or used up. Get a new one where you copied it.');
12
+ return {
13
+ create: (createdById) => store.transaction(async (tokens) => {
14
+ const now = clock.now();
15
+ const token = `${CREDENTIAL_PREFIXES.download}${randomBytes(32).toString('base64url')}`;
16
+ const expiresAt = new Date(now.getTime() + DOWNLOAD_TOKEN_TTL_MS).toISOString();
17
+ await tokens.insert({
18
+ id: ids.next(),
19
+ tokenHash: hashCredential(token),
20
+ createdById,
21
+ target: null,
22
+ downloads: 0,
23
+ expiresAt,
24
+ createdAt: now.toISOString(),
25
+ });
26
+ return {
27
+ token,
28
+ expiresAt,
29
+ maxDownloads: DOWNLOAD_TOKEN_MAX_DOWNLOADS,
30
+ };
31
+ }),
32
+ admit: (token, request) => store.transaction(async (tokens) => {
33
+ if (request.product !== undefined && request.product !== product)
34
+ throw invalid(`A download token downloads only ${product}.`);
35
+ const record = token
36
+ ? await tokens.findByHash(hashCredential(token))
37
+ : undefined;
38
+ const downloads = Number(record?.downloads ?? 0);
39
+ if (!record ||
40
+ Date.parse(record.expiresAt) <= clock.now().getTime() ||
41
+ downloads >= DOWNLOAD_TOKEN_MAX_DOWNLOADS)
42
+ throw spent();
43
+ const { target } = request;
44
+ if (target === undefined && !request.download)
45
+ return;
46
+ if (target !== undefined &&
47
+ record.target !== null &&
48
+ record.target !== target)
49
+ throw invalid(`This download token is for ${record.target}, not ${target}.`);
50
+ if ((target === undefined || record.target === target) &&
51
+ !request.download)
52
+ return;
53
+ // Binds the platform and counts the download; a concurrent request that changed the row first wins.
54
+ const updated = await tokens.updateIfDownloads(record.id, downloads, {
55
+ target: target ?? record.target,
56
+ downloads: request.download ? downloads + 1 : downloads,
57
+ });
58
+ if (!updated)
59
+ throw spent();
60
+ }),
61
+ };
62
+ }
63
+ function hashCredential(value) {
64
+ return createHash('sha256').update(value, 'utf8').digest('hex');
65
+ }
66
+ //# sourceMappingURL=download-tokens.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"download-tokens.js","sourceRoot":"","sources":["../src/download-tokens.ts"],"names":[],"mappings":"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"}
package/dist/http.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ import { Hono } from 'hono';
2
+ export declare function distributionRouter(): Hono;
3
+ //# sourceMappingURL=http.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,wBAAgB,kBAAkB,IAAI,IAAI,CAmBzC"}
package/dist/http.js ADDED
@@ -0,0 +1,19 @@
1
+ import { ProtocolError } from '@nocobase/agent-protocol';
2
+ import { ApiError, apiErrorHandler } from '@nocobase/app-server/router';
3
+ import { Hono } from 'hono';
4
+ export function distributionRouter() {
5
+ const router = new Hono();
6
+ router.onError((error, context) => apiErrorHandler(error instanceof ProtocolError
7
+ ? new ApiError({
8
+ status: error.apiStatus,
9
+ reason: error.code,
10
+ domain: error.domain,
11
+ message: error.message,
12
+ ...(error.details ? { metadata: error.details } : {}),
13
+ httpStatus: error.status,
14
+ cause: error,
15
+ })
16
+ : error, context));
17
+ return router;
18
+ }
19
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AACxE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,MAAM,UAAU,kBAAkB;IAChC,MAAM,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;IAC1B,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,CAChC,eAAe,CACb,KAAK,YAAY,aAAa;QAC5B,CAAC,CAAC,IAAI,QAAQ,CAAC;YACX,MAAM,EAAE,KAAK,CAAC,SAAS;YACvB,MAAM,EAAE,KAAK,CAAC,IAAI;YAClB,MAAM,EAAE,KAAK,CAAC,MAAM;YACpB,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACrD,UAAU,EAAE,KAAK,CAAC,MAA8B;YAChD,KAAK,EAAE,KAAK;SACb,CAAC;QACJ,CAAC,CAAC,KAAK,EACT,OAAO,CACR,CACF,CAAC;IACF,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,6 @@
1
+ export * from './artifacts.js';
2
+ export * from './download-tokens.js';
3
+ export * from './routes.js';
4
+ export * from './install.js';
5
+ export { DistTargetParams, DistFileParams, DistTargetQuery, DownloadTokenSchema, } from './schemas.js';
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,sBAAsB,CAAC;AACrC,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,OAAO,EACL,gBAAgB,EAChB,cAAc,EACd,eAAe,EACf,mBAAmB,GACpB,MAAM,cAAc,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ export * from './artifacts.js';
2
+ export * from './download-tokens.js';
3
+ export * from './routes.js';
4
+ export * from './install.js';
5
+ export { DistTargetParams, DistFileParams, DistTargetQuery, DownloadTokenSchema, } from './schemas.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,sBAAsB,CAAC;AACrC,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,OAAO,EACL,gBAAgB,EAChB,cAAc,EACd,eAAe,EACf,mBAAmB,GACpB,MAAM,cAAc,CAAC"}
@@ -0,0 +1,41 @@
1
+ import { type DescribeRouteOptions } from '@nocobase/app-server/router';
2
+ import { Hono, type Context } from 'hono';
3
+ /** Trusted host-authored shell fragments; never derive these from requests or configuration. */
4
+ export interface InstallScriptExtensions {
5
+ readonly intro?: string;
6
+ readonly usage?: string;
7
+ readonly command?: string;
8
+ readonly name?: string;
9
+ readonly prefix?: string;
10
+ readonly variables?: string;
11
+ readonly parseServer?: string;
12
+ readonly parseRunner?: string;
13
+ readonly parsePrefix?: string;
14
+ readonly parseService?: string;
15
+ readonly validate?: string;
16
+ readonly defaultPrefix?: string;
17
+ readonly credentials?: string;
18
+ readonly pnpm?: string;
19
+ readonly registered?: string;
20
+ readonly resolveFailure?: string;
21
+ readonly afterCli?: string;
22
+ readonly next?: string;
23
+ readonly productComment?: string;
24
+ readonly npmInstallComment?: string;
25
+ }
26
+ export interface InstallScriptOptions {
27
+ readonly cli: string;
28
+ readonly server?: string;
29
+ readonly extensions?: InstallScriptExtensions;
30
+ }
31
+ export declare function installScript(options: InstallScriptOptions): string;
32
+ export interface InstallRoutesOptions {
33
+ readonly cli: () => string;
34
+ readonly publicOrigin?: () => string | undefined;
35
+ readonly publicBasePath?: string;
36
+ readonly extensions?: InstallScriptExtensions;
37
+ readonly openapi?: DescribeRouteOptions;
38
+ }
39
+ export declare function requestedServer(context: Context, options?: Pick<InstallRoutesOptions, 'publicOrigin' | 'publicBasePath'>): string;
40
+ export declare function createInstallRoutes(options: InstallRoutesOptions): Hono;
41
+ //# sourceMappingURL=install.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../src/install.ts"],"names":[],"mappings":"AAMA,OAAO,EAIL,KAAK,oBAAoB,EAC1B,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,KAAK,OAAO,EAAE,MAAM,MAAM,CAAC;AAE1C,gGAAgG;AAChG,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;CACrC;AACD,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,UAAU,CAAC,EAAE,uBAAuB,CAAC;CAC/C;AACD,wBAAgB,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,MAAM,CAkBnE;AACD,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,GAAG,EAAE,MAAM,MAAM,CAAC;IAC3B,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,MAAM,GAAG,SAAS,CAAC;IACjD,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,UAAU,CAAC,EAAE,uBAAuB,CAAC;IAC9C,QAAQ,CAAC,OAAO,CAAC,EAAE,oBAAoB,CAAC;CACzC;AACD,wBAAgB,eAAe,CAC7B,OAAO,EAAE,OAAO,EAChB,OAAO,GAAE,IAAI,CAAC,oBAAoB,EAAE,cAAc,GAAG,gBAAgB,CAAM,GAC1E,MAAM,CA2BR;AA0PD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,oBAAoB,GAAG,IAAI,CAmCvE"}
@@ -0,0 +1,318 @@
1
+ import { DIST_PRODUCT_PATTERN, DIST_ROUTES, HEADERS, } from '@nocobase/agent-protocol';
2
+ import { npmLauncherScript } from '@nocobase/app-cli-client/install';
3
+ import { apiErrorResponse, cliRoute, describeRoute, } from '@nocobase/app-server/router';
4
+ import { Hono } from 'hono';
5
+ const SAFE_SERVER = /^https?:\/\/[A-Za-z0-9.:[\]_-]+(?:\/[A-Za-z0-9._~/-]*)?$/u;
6
+ export function installScript(options) {
7
+ if (!DIST_PRODUCT_PATTERN.test(options.cli) ||
8
+ options.cli === 'nocobase-runner')
9
+ throw new Error(`Not a CLI command name: ${options.cli}`);
10
+ const server = options.server ?? '';
11
+ const fallback = SAFE_SERVER.test(server) ? server.replace(/\/+$/u, '') : '';
12
+ const extensions = { ...DEFAULT_EXTENSIONS, ...options.extensions };
13
+ return INSTALL_SCRIPT_TEMPLATE.replace(/@([A-Za-z]+)@/gu, (marker, key) => key in extensions
14
+ ? (extensions[key] ?? '')
15
+ : marker)
16
+ .replaceAll('@CLI@', options.cli)
17
+ .replace('@DEFAULT_SERVER@', fallback);
18
+ }
19
+ export function requestedServer(context, options = {}) {
20
+ const url = new URL(context.req.url);
21
+ const configured = options.publicOrigin?.();
22
+ let origin;
23
+ if (configured)
24
+ origin = configured.replace(/\/+$/u, '');
25
+ else {
26
+ const proto = context.req
27
+ .header('x-forwarded-proto')
28
+ ?.split(',')[0]
29
+ ?.trim();
30
+ const host = context.req.header('x-forwarded-host')?.split(',')[0]?.trim() ??
31
+ context.req.header('host') ??
32
+ url.host;
33
+ const protocol = proto === 'https' || proto === 'http'
34
+ ? proto
35
+ : url.protocol.replace(/:$/u, '');
36
+ origin = `${protocol}://${host}`;
37
+ }
38
+ const base = options.publicBasePath !== undefined
39
+ ? options.publicBasePath.replace(/\/+$/u, '')
40
+ : url.pathname.endsWith(DIST_ROUTES.installScript)
41
+ ? url.pathname.slice(0, -DIST_ROUTES.installScript.length)
42
+ : '';
43
+ return `${origin}${base}`;
44
+ }
45
+ const DEFAULT_EXTENSIONS = {
46
+ intro: `# Installs the @CLI@ CLI this application serves.
47
+ # curl -fsSL <server>/api/agents/dist/installScript | sh -s -- --token <download token> [options]
48
+ `,
49
+ usage: `Usage: install.sh --token <token> [--server <url>] [options]
50
+
51
+ --token <token> A download token for the CLI
52
+ --server <url> The application (defaults to the script's application)
53
+ --prefix <dir> Where to install @CLI@ (default: ~/.local/share/@CLI@, or NOCOBASE_CLI_INSTALL_DIR)
54
+ --bin-dir <dir> Where to link the command (default: ~/.local/bin, or NOCOBASE_CLI_BIN_DIR)
55
+ --dry-run Print what would be done, and change nothing`,
56
+ command: ``,
57
+ name: ``,
58
+ prefix: ``,
59
+ variables: ``,
60
+ parseServer: ` --server) server="\${2:-}"; shift 2 ;;`,
61
+ parseRunner: ``,
62
+ parsePrefix: ``,
63
+ parseService: ``,
64
+ validate: ``,
65
+ defaultPrefix: ``,
66
+ credentials: `header="${HEADERS.downloadToken}"
67
+ `,
68
+ pnpm: ``,
69
+ registered: ``,
70
+ resolveFailure: ` if [ "$status" = 401 ] && [ -x "$dir/current/bin/$product" ]; then
71
+ say "The token was not accepted (used up or expired), but $product is installed in $dir already; run \\"$product update\\" to update it."
72
+ installed=kept
73
+ return 0
74
+ elif [ "$status" != 200 ]; then
75
+ message="$(sed -n 's/.*"message":"\\([^"]*\\)".*/\\1/p' "$tmp/resolve")"
76
+ fail "$server answered $status: \${message:-$(cat "$tmp/resolve")}"
77
+ fi`,
78
+ afterCli: `say "$cli is installed: $bin_dir/$cli"
79
+ `,
80
+ next: `say "Next: $cli login --server $server"`,
81
+ npmInstallComment: ` # Optional platform binaries are not needed by this installation.`,
82
+ productComment: `# Installs one product and records its installation.
83
+ `,
84
+ };
85
+ const INSTALL_SCRIPT_TEMPLATE = `#!/bin/sh
86
+ @intro@set -eu
87
+
88
+ usage() {
89
+ cat <<'USAGE'
90
+ @usage@
91
+ USAGE
92
+ }
93
+
94
+ cli=@CLI@
95
+ @command@
96
+ server="@DEFAULT_SERVER@"
97
+ server_explicit=0
98
+ token=""
99
+ @name@
100
+ prefix="\${NOCOBASE_CLI_INSTALL_DIR:-}"
101
+ @prefix@
102
+ bin_dir="\${NOCOBASE_CLI_BIN_DIR:-}"
103
+ @variables@
104
+ dry_run=0
105
+ while [ $# -gt 0 ]; do
106
+ case "$1" in
107
+ @parseServer@
108
+ --token) token="\${2:-}"; shift 2 ;;
109
+ @parseRunner@
110
+ --prefix) prefix="\${2:-}"; shift 2 ;;
111
+ @parsePrefix@
112
+ --bin-dir) bin_dir="\${2:-}"; shift 2 ;;
113
+ @parseService@
114
+ --dry-run) dry_run=1; shift ;;
115
+ -h|--help) usage; exit 0 ;;
116
+ *) echo "Unknown option: $1" >&2; usage >&2; exit 2 ;;
117
+ esac
118
+ done
119
+ @validate@
120
+ if [ -z "$server" ] || [ -z "$token" ]; then
121
+ usage >&2
122
+ exit 2
123
+ fi
124
+ server="\${server%/}"
125
+ prefix="\${prefix:-$HOME/.local/share/$cli}"
126
+ @defaultPrefix@
127
+ bin_dir="\${bin_dir:-$HOME/.local/bin}"
128
+
129
+ say() { printf '%s\\n' "$*"; }
130
+ fail() { printf '%s install: %s\\n' "$cli" "$*" >&2; exit 1; }
131
+ run() {
132
+ if [ "$dry_run" = 1 ]; then
133
+ say "+ $*"
134
+ else
135
+ "$@"
136
+ fi
137
+ }
138
+
139
+ @credentials@
140
+ case "$(uname -s)" in
141
+ Darwin) os=darwin ;;
142
+ Linux) os=linux ;;
143
+ *) fail "$cli runs on macOS and Linux, not on $(uname -s). On Windows, use WSL." ;;
144
+ esac
145
+ case "$(uname -m)" in
146
+ arm64|aarch64) arch=arm64 ;;
147
+ x86_64|amd64) arch=x64 ;;
148
+ *) fail "Unsupported processor: $(uname -m)." ;;
149
+ esac
150
+ target="\${NOCOBASE_CLI_TARGET:-$os-$arch}"
151
+
152
+ command -v curl >/dev/null 2>&1 || fail "curl is required."
153
+ command -v tar >/dev/null 2>&1 || fail "tar is required."
154
+ if command -v sha256sum >/dev/null 2>&1; then
155
+ sha256() { sha256sum "$1" | cut -d ' ' -f 1; }
156
+ elif command -v shasum >/dev/null 2>&1; then
157
+ sha256() { shasum -a 256 "$1" | cut -d ' ' -f 1; }
158
+ else
159
+ fail "sha256sum or shasum is required to check the download."
160
+ fi
161
+
162
+ @pnpm@
163
+ tmp="$(mktemp -d)"
164
+ trap 'rm -rf "$tmp"' EXIT INT TERM
165
+ @registered@
166
+ field() { sed -n "s/^$1=//p" "$tmp/resolve" | head -n 1; }
167
+
168
+ # A universal package carries no Node: sets node_bin to the node on PATH when it is Node.js 24 or newer, and fails
169
+ # saying how to install one otherwise. require_node <command>.
170
+ require_node() {
171
+ node_hint="Install Node.js 24 or newer (https://nodejs.org/en/download, or with a version manager: nvm install 24), open a new shell so that node is on PATH, and run this command again."
172
+ node_bin="$(command -v node 2>/dev/null || true)"
173
+ [ -n "$node_bin" ] || fail "$1 needs Node.js 24 or newer, and node is not on PATH. $node_hint"
174
+ node_version="$("$node_bin" -p 'process.versions.node' 2>/dev/null || true)"
175
+ case "$node_version" in
176
+ ''|*[!0-9.]*) fail "$1 needs Node.js 24 or newer, and $node_bin does not say its version. $node_hint" ;;
177
+ esac
178
+ [ "\${node_version%%.*}" -ge 24 ] || fail "$1 needs Node.js 24 or newer; $node_bin is $node_version. $node_hint"
179
+ }
180
+
181
+ # A package the application names on npm is installed with npm: sets npm_bin to NOCOBASE_NPM or the npm on PATH, and
182
+ # fails saying how to get one otherwise. require_npm <command>.
183
+ require_npm() {
184
+ npm_bin="\${NOCOBASE_NPM:-$(command -v npm 2>/dev/null || true)}"
185
+ if [ -z "$npm_bin" ] || [ ! -x "$npm_bin" ]; then
186
+ fail "$1 is installed from npm, and npm is not on PATH. npm comes with Node.js: install Node.js 24 or newer from https://nodejs.org/en/download (a version manager such as nvm installs npm too), or set NOCOBASE_NPM to its path, and run this command again."
187
+ fi
188
+ }
189
+
190
+ # The launcher of a version installed from npm: <version>/bin/<command> starts node_modules/.bin/<command> with the
191
+ # first Node.js 24 or newer it finds, as the universal tarball's launcher does.
192
+ write_npm_launcher() {
193
+ cat <<'LAUNCHER'
194
+ ${npmLauncherScript()}LAUNCHER
195
+ }
196
+
197
+ @productComment@install_product() {
198
+ product="$1"
199
+ dir="$2"
200
+ mode="$3"
201
+ installed=new
202
+ status="$(curl -sS -o "$tmp/resolve" -w '%{http_code}' \\
203
+ -H "$header: $token" \\
204
+ "$server/api/agents/dist/products/$product/targets/$target?format=env&accept=npm")" ||
205
+ fail "Could not reach $server."
206
+ @resolveFailure@
207
+ kind="$(field kind)"
208
+ version="$(field version)"
209
+ case "$version" in
210
+ ''|*[!0-9A-Za-z.+-]*) fail "The server named an unexpected version: $version" ;;
211
+ esac
212
+ universal=""
213
+ if [ "$kind" = npm ]; then
214
+ package="$(field package)"
215
+ case "$package" in
216
+ ''|*[!0-9a-z@/._~-]*) fail "The server named an unexpected npm package: $package" ;;
217
+ esac
218
+ require_node "$product"
219
+ require_npm "$product"
220
+ say "$product $version comes from npm ($package@$version) and runs on this machine's Node.js $node_version ($node_bin)."
221
+ else
222
+ url="$(field url)"
223
+ checksum="$(field sha256)"
224
+ case "$url" in
225
+ /*) ;;
226
+ *) fail "The server named an unexpected download: $url" ;;
227
+ esac
228
+ case "$checksum" in
229
+ *[!0-9a-f]*|'') fail "The server named an unexpected checksum: $checksum" ;;
230
+ esac
231
+ universal="$(field universal)"
232
+ if [ "$universal" = true ]; then
233
+ require_node "$product"
234
+ say "$product $version runs on this machine's Node.js $node_version ($node_bin)."
235
+ fi
236
+ fi
237
+
238
+ dest="$dir/versions/$version"
239
+ if [ -x "$dest/bin/$product" ]; then
240
+ say "$product $version for $target is already installed in $dest."
241
+ elif [ "$kind" = npm ]; then
242
+ say "Installing $package@$version with npm ..."
243
+ run rm -rf "$dest.partial"
244
+ run mkdir -p "$dest.partial"
245
+ @npmInstallComment@
246
+ run "$npm_bin" install --prefix "$dest.partial" --no-save --no-audit --no-fund --omit=optional "$package@$version"
247
+ if [ "$dry_run" = 0 ]; then
248
+ [ -e "$dest.partial/node_modules/.bin/$product" ] || fail "$package@$version provides no $product command."
249
+ mkdir -p "$dest.partial/bin"
250
+ write_npm_launcher >"$dest.partial/bin/$product"
251
+ chmod 755 "$dest.partial/bin/$product"
252
+ fi
253
+ run mv "$dest.partial" "$dest"
254
+ else
255
+ say "Downloading $product $version for $target from $server ..."
256
+ run curl -fSL --progress-bar -H "$header: $token" -o "$tmp/$product.tar.gz" "$server$url"
257
+ if [ "$dry_run" = 0 ]; then
258
+ actual="$(sha256 "$tmp/$product.tar.gz")"
259
+ [ "$actual" = "$checksum" ] || fail "The download does not match its SHA-256 (expected $checksum, got $actual)."
260
+ say "Checksum verified."
261
+ fi
262
+ run rm -rf "$dest.partial"
263
+ run mkdir -p "$dest.partial"
264
+ run tar -xzf "$tmp/$product.tar.gz" -C "$dest.partial" --strip-components=1
265
+ run mv "$dest.partial" "$dest"
266
+ fi
267
+ run ln -sfn "versions/$version" "$dir/current"
268
+ if [ "$universal" = true ] || [ "$kind" = npm ]; then
269
+ # The launcher's first choice, so a service that does not have this shell's PATH runs the same Node.
270
+ run ln -sfn "$node_bin" "$dir/node"
271
+ fi
272
+ run mkdir -p "$bin_dir"
273
+ run ln -sfn "$dir/current/bin/$product" "$bin_dir/$product"
274
+ if [ "$dry_run" = 0 ]; then
275
+ printf '{\\n "prefix": "%s",\\n "binLink": "%s",\\n "mode": "%s"\\n}\\n' "$dir" "$bin_dir/$product" "$mode" >"$dir/install.json"
276
+ fi
277
+ }
278
+
279
+ # 1. The CLI.
280
+ previous_cli="$(readlink "$prefix/current" 2>/dev/null || true)"
281
+ install_product "$cli" "$prefix" cli
282
+ # Reuse the saved ACP service definitions after switching current, including every profile.
283
+ if [ "$installed" = new ] && [ "$previous_cli" != "$(readlink "$prefix/current" 2>/dev/null || true)" ]; then
284
+ run "$prefix/current/bin/$cli" acp service restart || say "Could not restart background connections. Run $cli acp service restart to retry."
285
+ fi
286
+ @afterCli@
287
+ case ":$PATH:" in
288
+ *":$bin_dir:"*) ;;
289
+ *) say "Add $bin_dir to your PATH to run $cli from a shell: export PATH=\\"$bin_dir:\\$PATH\\"" ;;
290
+ esac
291
+ @next@
292
+ `;
293
+ export function createInstallRoutes(options) {
294
+ const router = new Hono();
295
+ router.get('/installScript', describeRoute(options.openapi ?? {
296
+ tags: ['CliDistribution'],
297
+ summary: 'Get the CLI install script',
298
+ operationId: 'cliDistributionInstallScript',
299
+ ...cliRoute(false),
300
+ security: [],
301
+ responses: {
302
+ 200: {
303
+ description: 'A POSIX shell script.',
304
+ content: { 'text/x-shellscript': { schema: { type: 'string' } } },
305
+ },
306
+ 500: apiErrorResponse(500),
307
+ },
308
+ }), (context) => context.body(installScript({
309
+ cli: options.cli(),
310
+ server: requestedServer(context, options),
311
+ ...(options.extensions ? { extensions: options.extensions } : {}),
312
+ }), 200, {
313
+ 'content-type': 'text/x-shellscript; charset=utf-8',
314
+ 'cache-control': 'no-cache',
315
+ }));
316
+ return router;
317
+ }
318
+ //# sourceMappingURL=install.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.js","sourceRoot":"","sources":["../src/install.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import { type DescribeRouteOptions } from '@nocobase/app-server/router';
2
+ import { Hono } from 'hono';
3
+ export interface PublicInstallScriptOptions {
4
+ readonly cli: string;
5
+ readonly server?: string;
6
+ }
7
+ /** A separate CLI-only installer. It neither changes nor extends the protected installation protocol. */
8
+ export declare function publicInstallScript(options: PublicInstallScriptOptions): string;
9
+ export interface PublicInstallRoutesOptions {
10
+ readonly cli: () => string;
11
+ readonly publicOrigin?: () => string | undefined;
12
+ readonly publicBasePath?: string;
13
+ readonly openapi?: DescribeRouteOptions;
14
+ }
15
+ /** Mount explicitly alongside a host's independently configured public artifact admission. */
16
+ export declare function createPublicInstallRoutes(options: PublicInstallRoutesOptions): Hono;
17
+ //# sourceMappingURL=public-install.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"public-install.d.ts","sourceRoot":"","sources":["../src/public-install.ts"],"names":[],"mappings":"AAEA,OAAO,EAIL,KAAK,oBAAoB,EAC1B,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAK5B,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,yGAAyG;AACzG,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,0BAA0B,GAClC,MAAM,CAWR;AAED,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,GAAG,EAAE,MAAM,MAAM,CAAC;IAC3B,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,MAAM,GAAG,SAAS,CAAC;IACjD,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,OAAO,CAAC,EAAE,oBAAoB,CAAC;CACzC;AAED,8FAA8F;AAC9F,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,0BAA0B,GAClC,IAAI,CAgCN"}