@microteia/console 2.7.0
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/CONSOLE-VERSIONS.md +85 -0
- package/README.md +64 -0
- package/lib/console/backendEnv.d.ts +52 -0
- package/lib/console/backendEnv.js +118 -0
- package/lib/console/backendIndexes.d.ts +40 -0
- package/lib/console/backendIndexes.js +178 -0
- package/lib/console/backendParameters.d.ts +48 -0
- package/lib/console/backendParameters.js +100 -0
- package/lib/console/callableAccess.d.ts +39 -0
- package/lib/console/callableAccess.js +61 -0
- package/lib/console/channel.d.ts +49 -0
- package/lib/console/channel.js +145 -0
- package/lib/console/connect.d.ts +2 -0
- package/lib/console/connect.js +74 -0
- package/lib/console/customFunctions.d.ts +120 -0
- package/lib/console/customFunctions.js +298 -0
- package/lib/console/deploy.d.ts +2 -0
- package/lib/console/deploy.js +261 -0
- package/lib/console/deployFunctions.d.ts +45 -0
- package/lib/console/deployFunctions.js +204 -0
- package/lib/console/environment.d.ts +62 -0
- package/lib/console/environment.js +151 -0
- package/lib/console/firebaseCli.d.ts +15 -0
- package/lib/console/firebaseCli.js +90 -0
- package/lib/console/firestoreRest.d.ts +39 -0
- package/lib/console/firestoreRest.js +131 -0
- package/lib/console/hostingCheck.d.ts +29 -0
- package/lib/console/hostingCheck.js +44 -0
- package/lib/console/init.d.ts +2 -0
- package/lib/console/init.js +60 -0
- package/lib/console/pluginWorkspace.d.ts +48 -0
- package/lib/console/pluginWorkspace.js +148 -0
- package/lib/console/provision.d.ts +70 -0
- package/lib/console/provision.js +478 -0
- package/lib/console/regionOrphans.d.ts +43 -0
- package/lib/console/regionOrphans.js +99 -0
- package/lib/console/runtimeConfigShape.d.ts +25 -0
- package/lib/console/runtimeConfigShape.js +35 -0
- package/lib/console/unpack.d.ts +9 -0
- package/lib/console/unpack.js +333 -0
- package/lib/console/versions.d.ts +10 -0
- package/lib/console/versions.js +72 -0
- package/lib/console/workspace.d.ts +19 -0
- package/lib/console/workspace.js +33 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +136 -0
- package/lib/kernel/backendShape.d.ts +74 -0
- package/lib/kernel/backendShape.js +91 -0
- package/lib/kernel/channel.d.ts +79 -0
- package/lib/kernel/channel.js +157 -0
- package/lib/kernel/manifest.d.ts +138 -0
- package/lib/kernel/manifest.js +145 -0
- package/lib/shared/args.d.ts +14 -0
- package/lib/shared/args.js +44 -0
- package/lib/shared/digest.d.ts +30 -0
- package/lib/shared/digest.js +34 -0
- package/lib/shared/paths.d.ts +90 -0
- package/lib/shared/paths.js +97 -0
- package/lib/shared/run.d.ts +28 -0
- package/lib/shared/run.js +49 -0
- package/lib/shared/ui.d.ts +23 -0
- package/lib/shared/ui.js +43 -0
- package/lib/vendor/authoringGuide.d.ts +19 -0
- package/lib/vendor/authoringGuide.js +284 -0
- package/lib/vendor/bundleAudit.d.ts +19 -0
- package/lib/vendor/bundleAudit.js +95 -0
- package/lib/vendor/changelogs.d.ts +62 -0
- package/lib/vendor/changelogs.js +131 -0
- package/lib/vendor/exampleSources.d.ts +29 -0
- package/lib/vendor/exampleSources.js +126 -0
- package/lib/vendor/installationDocs.d.ts +35 -0
- package/lib/vendor/installationDocs.js +243 -0
- package/lib/vendor/pack.d.ts +2 -0
- package/lib/vendor/pack.js +276 -0
- package/lib/vendor/packConsole.d.ts +13 -0
- package/lib/vendor/packConsole.js +63 -0
- package/lib/vendor/packageTemplates.d.ts +66 -0
- package/lib/vendor/packageTemplates.js +200 -0
- package/lib/vendor/pluginWorkspaceTemplates.d.ts +19 -0
- package/lib/vendor/pluginWorkspaceTemplates.js +29 -0
- package/lib/vendor/publish.d.ts +2 -0
- package/lib/vendor/publish.js +277 -0
- package/lib/vendor/repository.d.ts +9 -0
- package/lib/vendor/repository.js +26 -0
- package/package.json +21 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* O pouco que o CONSOLE sabe sobre `extensions/`.
|
|
3
|
+
*
|
|
4
|
+
* Tudo o que descreve o kernel — `AGENTS.md`, `AUTHORING.md`, `tsconfig.json`, `.mcp.json`, os scripts
|
|
5
|
+
* — morava aqui, e era o lado errado. O Console é versionado (`CLI_VERSION`) e distribuído SEPARADAMENTE
|
|
6
|
+
* do kernel: um Console de duas versões atrás ao lado de uma instalação nova escrevia, em silêncio, a
|
|
7
|
+
* documentação de outro contrato. Passou para `src/sdk/node/workspace/`, que viaja no mesmo `.tgz` que
|
|
8
|
+
* os pontos de extensão que o texto descreve, e é reescrito a cada troca de kernel.
|
|
9
|
+
*
|
|
10
|
+
* Sobrou o que só o Console tem como saber: onde está o tarball do SDK dentro do pacote, e o nome do
|
|
11
|
+
* escritório. É a semente — mínima de propósito, porque quem a completa é o `sync`.
|
|
12
|
+
*/
|
|
13
|
+
export const SDK_TARBALL = 'microteia-sdk.tgz';
|
|
14
|
+
/**
|
|
15
|
+
* A semente do `package.json`. Não traz scripts nem devDependencies: os nomes de comando são do SDK, e
|
|
16
|
+
* duplicá-los aqui era exatamente o problema. O `sync` os acrescenta logo depois do `npm install`, e o
|
|
17
|
+
* segundo `npm install` os instala.
|
|
18
|
+
*/
|
|
19
|
+
export const workspacePackageJson = (officeName, sdkPath) => JSON.stringify({
|
|
20
|
+
name: `${officeName}-extensions`,
|
|
21
|
+
version: '0.0.0',
|
|
22
|
+
private: true,
|
|
23
|
+
description: 'Microteia extensions authored by this organization.',
|
|
24
|
+
dependencies: {
|
|
25
|
+
// Caminho SEM versão de propósito: um kernel novo não obriga ninguém a editar este arquivo. O que
|
|
26
|
+
// traz o SDK novo é `npm run sdk:refresh` — ou o `microteia unpack`, que o faz sozinho.
|
|
27
|
+
'@microteia/sdk': `file:${sdkPath}`,
|
|
28
|
+
},
|
|
29
|
+
}, null, 2) + '\n';
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
import { access, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { flagValue, hasFlag } from '../shared/args.js';
|
|
5
|
+
import { CLI_VERSION, repoRoot } from '../shared/paths.js';
|
|
6
|
+
import { capture, captureOrThrow, run } from '../shared/run.js';
|
|
7
|
+
import { blank, bullets, heading, info, pending, step, success, warn } from '../shared/ui.js';
|
|
8
|
+
import { digestMismatch, digestOfFile } from '../shared/digest.js';
|
|
9
|
+
import { emptyIndex, entryOf, kernelTarballName, parseIndex, serializeIndex, withEntry, } from '../kernel/channel.js';
|
|
10
|
+
import { CONSOLE_CHANGELOG, KERNEL_CHANGELOG, changelogEntry, readChangelog } from './changelogs.js';
|
|
11
|
+
import { CONSOLE_PACKAGE_NAME } from './packageTemplates.js';
|
|
12
|
+
import { assertInsideRepository } from './repository.js';
|
|
13
|
+
/**
|
|
14
|
+
* `microteia publish` — põe no ar o que o `pack` e o `pack-console` já produziram.
|
|
15
|
+
*
|
|
16
|
+
* Ele NÃO constrói. A separação é a mesma que existe entre `unpack` e `deploy` do outro lado, e pela
|
|
17
|
+
* mesma razão: o `pack` é que roda o gate de qualidade, e um comando que constrói e publica no mesmo
|
|
18
|
+
* gesto não tem momento para alguém olhar o que saiu. Publicar é o passo em que já não há como voltar
|
|
19
|
+
* atrás — release é imutável —, então tudo o que pode recusar recusa antes de a primeira coisa subir.
|
|
20
|
+
*
|
|
21
|
+
* A ordem é ARTEFATOS primeiro, CATÁLOGO depois. Um índice que aponta para um arquivo que não subiu
|
|
22
|
+
* quebra a instalação de todo mundo que pedir `latest`; um arquivo que subiu e que o índice ainda não
|
|
23
|
+
* menciona não quebra nada — ninguém o encontra até a publicação terminar, e ela é retomável.
|
|
24
|
+
*/
|
|
25
|
+
/**
|
|
26
|
+
* O repositório dos releases é SÓ de releases: nenhuma linha de fonte do kernel mora nele. Os artefatos
|
|
27
|
+
* são compilados, mas o repositório que os hospeda é público, e a distância entre "público" e "fonte
|
|
28
|
+
* pública" tem de ser estrutural, não uma configuração que alguém pode errar.
|
|
29
|
+
*/
|
|
30
|
+
const RELEASES_REPO = 'microteia/releases';
|
|
31
|
+
/** O caminho do catálogo DENTRO daquele repositório. É o que o GitHub Pages serve. */
|
|
32
|
+
const INDEX_PATH = 'kernel/index.json';
|
|
33
|
+
const tagOf = (version) => `kernel-${version}`;
|
|
34
|
+
const assetUrl = (repo, version, name) => `https://github.com/${repo}/releases/download/${tagOf(version)}/${name}`;
|
|
35
|
+
const exists = async (path) => {
|
|
36
|
+
try {
|
|
37
|
+
await access(path);
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return false;
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
const readJson = async (path) => JSON.parse(await readFile(path, 'utf8'));
|
|
45
|
+
/**
|
|
46
|
+
* Lê o catálogo pela API de conteúdo, e não pela URL pública: o que interessa é o que está no
|
|
47
|
+
* repositório AGORA, e o Pages serve de um cache que pode estar minutos atrás. Publicar contra a
|
|
48
|
+
* versão em cache perderia a entrada de quem publicou antes.
|
|
49
|
+
*/
|
|
50
|
+
const readPublishedIndex = async (repo) => {
|
|
51
|
+
const result = await capture('gh', ['api', `repos/${repo}/contents/${INDEX_PATH}`]);
|
|
52
|
+
if (result.code !== 0) {
|
|
53
|
+
if (result.stderr.includes('Not Found') || result.stdout.includes('Not Found')) {
|
|
54
|
+
info(` ${INDEX_PATH} does not exist in ${repo} yet — this is the first published version`);
|
|
55
|
+
return { index: emptyIndex(), sha: null };
|
|
56
|
+
}
|
|
57
|
+
throw new Error(`Could not read ${INDEX_PATH} from ${repo}.\n${result.stderr.trim() || result.stdout.trim()}\n`
|
|
58
|
+
+ 'Is "gh" authenticated (gh auth status) and does the repository exist?');
|
|
59
|
+
}
|
|
60
|
+
const contents = JSON.parse(result.stdout);
|
|
61
|
+
const text = Buffer.from(contents.content, 'base64').toString('utf8');
|
|
62
|
+
return { index: parseIndex(text, `${repo}/${INDEX_PATH}`), sha: contents.sha };
|
|
63
|
+
};
|
|
64
|
+
const writePublishedIndex = async (repo, index, sha, version) => {
|
|
65
|
+
const content = Buffer.from(serializeIndex(index), 'utf8').toString('base64');
|
|
66
|
+
const args = [
|
|
67
|
+
'api', '--method', 'PUT', `repos/${repo}/contents/${INDEX_PATH}`,
|
|
68
|
+
'-f', `message=kernel ${version}`,
|
|
69
|
+
'-f', `content=${content}`,
|
|
70
|
+
];
|
|
71
|
+
if (sha !== null)
|
|
72
|
+
args.push('-f', `sha=${sha}`);
|
|
73
|
+
await captureOrThrow('gh', args);
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* O `gh` é a única ferramenta que este comando exige, e a falta dele apareceria como `spawn gh ENOENT`
|
|
77
|
+
* — que não diz o que instalar nem por quê. Mesma postura do `connect` com o `firebase`.
|
|
78
|
+
*/
|
|
79
|
+
const assertGitHubCli = async () => {
|
|
80
|
+
const result = await capture('gh', ['--version']).catch(() => null);
|
|
81
|
+
if (result === null || result.code !== 0) {
|
|
82
|
+
throw new Error('Publishing the kernel needs the GitHub CLI ("gh"), and it is not available here.\n'
|
|
83
|
+
+ ' brew install gh && gh auth login\n'
|
|
84
|
+
+ 'The Console does not need it: "microteia publish --console-only" goes to npm.');
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
const releaseExists = async (repo, version) => {
|
|
88
|
+
const result = await capture('gh', ['release', 'view', tagOf(version), '--repo', repo]);
|
|
89
|
+
return result.code === 0;
|
|
90
|
+
};
|
|
91
|
+
/**
|
|
92
|
+
* O pacote do kernel, conferido antes de qualquer coisa subir.
|
|
93
|
+
*
|
|
94
|
+
* O `sha256` é RECALCULADO do arquivo em vez de aceito do manifesto ao lado dele. Os dois foram escritos
|
|
95
|
+
* pelo mesmo `pack`, então em teoria concordam — e é justamente por isso que a conferência é barata: ela
|
|
96
|
+
* pega o caso em que alguém reconstruiu um dos dois e não o outro, que é o único jeito de um pacote
|
|
97
|
+
* publicado divergir do hash que o descreve.
|
|
98
|
+
*/
|
|
99
|
+
const readKernelPackage = async (root, version) => {
|
|
100
|
+
const directory = join(root, 'distributions', 'kernel', version);
|
|
101
|
+
const tarball = join(directory, kernelTarballName(version));
|
|
102
|
+
const manifestPath = join(directory, 'manifest.json');
|
|
103
|
+
for (const path of [tarball, manifestPath]) {
|
|
104
|
+
if (!await exists(path)) {
|
|
105
|
+
throw new Error(`${path} does not exist, and publishing does not build.\nRun "npm run pack:kernel" first.`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
const manifest = await readJson(manifestPath);
|
|
109
|
+
if (manifest.version !== version) {
|
|
110
|
+
throw new Error(`${manifestPath} describes ${manifest.version} and sits in the folder of ${version}.`);
|
|
111
|
+
}
|
|
112
|
+
if (manifest.tarball === undefined) {
|
|
113
|
+
throw new Error(`${manifestPath} carries no tarball digest, so what is published could not be verified after download.\n`
|
|
114
|
+
+ 'Rebuild the package with "npm run pack:kernel".');
|
|
115
|
+
}
|
|
116
|
+
const problem = digestMismatch(manifest.tarball, await digestOfFile(tarball));
|
|
117
|
+
if (problem !== null) {
|
|
118
|
+
throw new Error(`${tarball} does not match the manifest beside it: ${problem}\n`
|
|
119
|
+
+ 'One of the two was rebuilt without the other. Run "npm run pack:kernel" again.');
|
|
120
|
+
}
|
|
121
|
+
const changelog = await readChangelog(root, KERNEL_CHANGELOG, version);
|
|
122
|
+
return { manifest, tarball, entry: changelogEntry(changelog, version) };
|
|
123
|
+
};
|
|
124
|
+
const publishKernel = async (root, version, repo, dryRun) => {
|
|
125
|
+
await assertGitHubCli();
|
|
126
|
+
const { manifest, tarball, entry } = await readKernelPackage(root, version);
|
|
127
|
+
const directory = join(root, 'distributions', 'kernel', version);
|
|
128
|
+
const manifestPath = join(directory, 'manifest.json');
|
|
129
|
+
const published = await readPublishedIndex(repo);
|
|
130
|
+
const next = withEntry(published.index, entryOf(manifest, {
|
|
131
|
+
tarball: assetUrl(repo, version, kernelTarballName(version)),
|
|
132
|
+
manifest: assetUrl(repo, version, 'manifest.json'),
|
|
133
|
+
}, new Date().toISOString()));
|
|
134
|
+
success(`kernel ${version} verified: ${manifest.tarball?.bytes} bytes, sha256 ${manifest.tarball?.sha256.slice(0, 12)}…`);
|
|
135
|
+
info(` tag ${tagOf(version)} in ${repo}, and ${INDEX_PATH} promoting it to "latest"`);
|
|
136
|
+
if (dryRun) {
|
|
137
|
+
info(` the catalog would go from ${published.index.kernel.length} to ${next.kernel.length} version(s)`);
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
const notes = await mkdtemp(join(tmpdir(), 'microteia-publish-'));
|
|
141
|
+
const notesFile = join(notes, 'notes.md');
|
|
142
|
+
await writeFile(notesFile, entry);
|
|
143
|
+
try {
|
|
144
|
+
if (await releaseExists(repo, version)) {
|
|
145
|
+
/**
|
|
146
|
+
* O release existe e o catálogo não o menciona: é uma publicação interrompida entre os dois
|
|
147
|
+
* passos. Retomar é subir os arquivos por cima e escrever o índice — e não recusar, porque
|
|
148
|
+
* recusar deixaria a única saída sendo apagar o release à mão.
|
|
149
|
+
*/
|
|
150
|
+
warn(`${tagOf(version)} already exists in ${repo}, and the catalog does not list it`);
|
|
151
|
+
info(' completing the interrupted publish: re-uploading the assets and writing the catalog');
|
|
152
|
+
await run('gh', [
|
|
153
|
+
'release', 'upload', tagOf(version), tarball, manifestPath,
|
|
154
|
+
'--repo', repo, '--clobber',
|
|
155
|
+
]);
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
pending(`creating ${tagOf(version)} in ${repo}`);
|
|
159
|
+
await run('gh', [
|
|
160
|
+
'release', 'create', tagOf(version), tarball, manifestPath,
|
|
161
|
+
'--repo', repo,
|
|
162
|
+
'--title', `Microteia kernel ${version}`,
|
|
163
|
+
'--notes-file', notesFile,
|
|
164
|
+
]);
|
|
165
|
+
}
|
|
166
|
+
success(`assets published for ${version}`);
|
|
167
|
+
// O catálogo por último, sempre. Ver a nota de ordem no topo deste módulo.
|
|
168
|
+
await writePublishedIndex(repo, next, published.sha, version);
|
|
169
|
+
success(`${INDEX_PATH} updated — "microteia unpack --version latest" now takes ${version}`);
|
|
170
|
+
}
|
|
171
|
+
finally {
|
|
172
|
+
await rm(notes, { recursive: true, force: true });
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
const publishedConsoleVersion = async (version) => {
|
|
176
|
+
const result = await capture('npm', ['view', `${CONSOLE_PACKAGE_NAME}@${version}`, 'version']);
|
|
177
|
+
return result.code === 0 && result.stdout.trim() !== '';
|
|
178
|
+
};
|
|
179
|
+
/**
|
|
180
|
+
* O npm exige 2FA para publicar, e o código não pode ser adivinhado nem guardado — então ele ATRAVESSA
|
|
181
|
+
* o comando. Sem esta passagem, `microteia publish` era inutilizável sob a configuração padrão de uma
|
|
182
|
+
* conta npm: ele chamava `npm publish`, o registry respondia 403, e a única saída era rodar o `npm` à
|
|
183
|
+
* mão — o que pularia a conferência de histórico que este comando existe para fazer.
|
|
184
|
+
*
|
|
185
|
+
* A alternativa sem interação é um granular access token com "bypass 2FA", que é o caminho de CI. Os
|
|
186
|
+
* dois estão na recusa, porque quem esbarra nela não é obrigado a saber que existem.
|
|
187
|
+
*/
|
|
188
|
+
const publishConsole = async (root, dryRun, otp) => {
|
|
189
|
+
const directory = join(root, 'distributions', 'console', CLI_VERSION);
|
|
190
|
+
for (const relative of ['package.json', 'lib/index.js', CONSOLE_CHANGELOG]) {
|
|
191
|
+
if (!await exists(join(directory, relative))) {
|
|
192
|
+
throw new Error(`${join(directory, relative)} does not exist, and publishing does not build.\n`
|
|
193
|
+
+ 'Run "npm run pack:console" first.');
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
// O histórico é conferido aqui de novo, e não só no `pack-console`: as duas pastas de `distributions/`
|
|
197
|
+
// sobrevivem entre versões, e publicar a de ontem é possível.
|
|
198
|
+
await readChangelog(directory, CONSOLE_CHANGELOG, CLI_VERSION);
|
|
199
|
+
if (await publishedConsoleVersion(CLI_VERSION)) {
|
|
200
|
+
info(`${CONSOLE_PACKAGE_NAME}@${CLI_VERSION} is already on the registry — nothing to publish`);
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
success(`Console ${CLI_VERSION} ready to publish from ${directory}`);
|
|
204
|
+
if (dryRun) {
|
|
205
|
+
info(` it would run "npm publish" as ${CONSOLE_PACKAGE_NAME}@${CLI_VERSION}`);
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
pending(`publishing ${CONSOLE_PACKAGE_NAME}@${CLI_VERSION}`);
|
|
209
|
+
const args = otp === undefined ? ['publish'] : ['publish', `--otp=${otp}`];
|
|
210
|
+
/**
|
|
211
|
+
* A saída do `npm` vai direto para o terminal — é `run`, e não `capture`, porque o publish pode
|
|
212
|
+
* PERGUNTAR o código de dois fatores, e uma pergunta capturada é um comando travado. O preço é que o
|
|
213
|
+
* motivo da falha não chega aqui como texto: a primeira versão disto procurava "2fa" na mensagem do
|
|
214
|
+
* erro, e a mensagem do erro é só "Command failed (exit 1): npm publish". A ajuda que ela produzia
|
|
215
|
+
* nunca apareceu uma vez.
|
|
216
|
+
*
|
|
217
|
+
* Então a nota é impressa em TODA falha, e ela não afirma a causa: diz o que o registry exige, que é
|
|
218
|
+
* de longe o motivo mais comum de um publish recusado, e deixa o erro do npm — que está logo acima,
|
|
219
|
+
* na tela — dizer o resto.
|
|
220
|
+
*/
|
|
221
|
+
await run('npm', args, { cwd: directory }).catch((error) => {
|
|
222
|
+
blank();
|
|
223
|
+
info('npm refused the publish. Publishing to the registry needs ONE of these, and the error above');
|
|
224
|
+
info('says which is missing:');
|
|
225
|
+
bullets([
|
|
226
|
+
'two-factor authentication enabled on the account, and "microteia publish --otp <code>"',
|
|
227
|
+
'a granular access token with "bypass 2FA", scoped to @microteia with read and write',
|
|
228
|
+
]);
|
|
229
|
+
info('A plain token from "npm login" is not accepted for publishing.');
|
|
230
|
+
throw error;
|
|
231
|
+
});
|
|
232
|
+
success(`${CONSOLE_PACKAGE_NAME}@${CLI_VERSION} published — "npm i -g ${CONSOLE_PACKAGE_NAME}" takes it`);
|
|
233
|
+
};
|
|
234
|
+
export const publish = async (args) => {
|
|
235
|
+
await assertInsideRepository('publish');
|
|
236
|
+
const root = repoRoot;
|
|
237
|
+
const dryRun = hasFlag(args, 'dry-run');
|
|
238
|
+
const repo = flagValue(args, 'repo') ?? RELEASES_REPO;
|
|
239
|
+
const otp = flagValue(args, 'otp');
|
|
240
|
+
const kernelOnly = hasFlag(args, 'kernel-only');
|
|
241
|
+
const consoleOnly = hasFlag(args, 'console-only');
|
|
242
|
+
if (kernelOnly && consoleOnly) {
|
|
243
|
+
throw new Error('--kernel-only and --console-only cannot both be given.');
|
|
244
|
+
}
|
|
245
|
+
const pkg = await readJson(join(root, 'package.json'));
|
|
246
|
+
const what = consoleOnly
|
|
247
|
+
? `Console ${CLI_VERSION}`
|
|
248
|
+
: kernelOnly
|
|
249
|
+
? `kernel ${pkg.version}`
|
|
250
|
+
: `kernel ${pkg.version} and Console ${CLI_VERSION}`;
|
|
251
|
+
heading(dryRun ? `Publishing ${what} — dry run, nothing is written` : `Publishing ${what}`);
|
|
252
|
+
const total = consoleOnly || kernelOnly ? 1 : 2;
|
|
253
|
+
let index = 0;
|
|
254
|
+
if (!consoleOnly) {
|
|
255
|
+
index += 1;
|
|
256
|
+
step(index, total, `Kernel ${pkg.version} to ${repo}`);
|
|
257
|
+
await publishKernel(root, pkg.version, repo, dryRun);
|
|
258
|
+
}
|
|
259
|
+
if (!kernelOnly) {
|
|
260
|
+
index += 1;
|
|
261
|
+
step(index, total, `Console ${CLI_VERSION} to npm`);
|
|
262
|
+
await publishConsole(root, dryRun, otp);
|
|
263
|
+
}
|
|
264
|
+
blank();
|
|
265
|
+
if (dryRun) {
|
|
266
|
+
info('Nothing was published. Run it again without --dry-run.');
|
|
267
|
+
}
|
|
268
|
+
else {
|
|
269
|
+
info('Published. An office takes it with:');
|
|
270
|
+
bullets([
|
|
271
|
+
`npm i -g ${CONSOLE_PACKAGE_NAME}`,
|
|
272
|
+
'microteia unpack --version latest',
|
|
273
|
+
'microteia deploy',
|
|
274
|
+
]);
|
|
275
|
+
}
|
|
276
|
+
blank();
|
|
277
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Os comandos de PUBLICAÇÃO só existem dentro do repositório da Microteia — é dele que saem o
|
|
3
|
+
* frontend construído e as functions compiladas. Mas eles viajam no Console empacotado (o
|
|
4
|
+
* `index.js` importa todos os comandos), então rodar `pack` numa cópia solta é um erro provável.
|
|
5
|
+
*
|
|
6
|
+
* Sem esta guarda o erro era um `ENOENT ... package.json` cru, que não diz o que fazer e parece
|
|
7
|
+
* defeito da ferramenta em vez de comando aplicado no lugar errado.
|
|
8
|
+
*/
|
|
9
|
+
export declare const assertInsideRepository: (command: string) => Promise<void>;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { access, readFile } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { repoRoot } from '../shared/paths.js';
|
|
4
|
+
/**
|
|
5
|
+
* Os comandos de PUBLICAÇÃO só existem dentro do repositório da Microteia — é dele que saem o
|
|
6
|
+
* frontend construído e as functions compiladas. Mas eles viajam no Console empacotado (o
|
|
7
|
+
* `index.js` importa todos os comandos), então rodar `pack` numa cópia solta é um erro provável.
|
|
8
|
+
*
|
|
9
|
+
* Sem esta guarda o erro era um `ENOENT ... package.json` cru, que não diz o que fazer e parece
|
|
10
|
+
* defeito da ferramenta em vez de comando aplicado no lugar errado.
|
|
11
|
+
*/
|
|
12
|
+
export const assertInsideRepository = async (command) => {
|
|
13
|
+
const manifest = join(repoRoot, 'package.json');
|
|
14
|
+
try {
|
|
15
|
+
await access(manifest);
|
|
16
|
+
const parsed = JSON.parse(await readFile(manifest, 'utf8'));
|
|
17
|
+
if (parsed.name === 'microteia')
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
// Cai na mensagem abaixo: ausente e ilegível têm a mesma causa e a mesma saída.
|
|
22
|
+
}
|
|
23
|
+
throw new Error(`"microteia ${command}" builds from the Microteia repository, and this copy is not inside one.\n`
|
|
24
|
+
+ `Run it from a checkout of the repository (looked for ${manifest}).\n`
|
|
25
|
+
+ 'The Console alone installs and updates Microteia; it cannot build a package.');
|
|
26
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@microteia/console",
|
|
3
|
+
"version": "2.7.0",
|
|
4
|
+
"description": "Install and update Microteia in a Firebase project you own.",
|
|
5
|
+
"license": "UNLICENSED",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"microteia": "lib/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"lib",
|
|
12
|
+
"README.md",
|
|
13
|
+
"CONSOLE-VERSIONS.md"
|
|
14
|
+
],
|
|
15
|
+
"engines": {
|
|
16
|
+
"node": ">=22"
|
|
17
|
+
},
|
|
18
|
+
"publishConfig": {
|
|
19
|
+
"access": "public"
|
|
20
|
+
}
|
|
21
|
+
}
|