@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,276 @@
|
|
|
1
|
+
import { cp, mkdir, readdir, readFile, rename, rm, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { basename, join, relative } from 'node:path';
|
|
3
|
+
import { flagValue, hasFlag } from '../shared/args.js';
|
|
4
|
+
import { repoRoot } from '../shared/paths.js';
|
|
5
|
+
import { run } from '../shared/run.js';
|
|
6
|
+
import { blank, bullets, heading, info, step, success } from '../shared/ui.js';
|
|
7
|
+
import { DEFAULT_FUNCTIONS_REGION, KERNEL_COMPONENTS, KERNEL_DISTRIBUTION_ID, MANUAL_PREREQUISITES, MINIMUM_CLI_VERSION, REQUIRED_NODE_VERSION, callableFunctionNames, declaredParametersIn, exportedFunctionNames, parseKernelVersion, } from '../kernel/manifest.js';
|
|
8
|
+
import { digestOfFile } from '../shared/digest.js';
|
|
9
|
+
import { kernelTarballName } from '../kernel/channel.js';
|
|
10
|
+
import { baselineFunctionsOf, baselineIndexesOf, claimProblems, claimsFromTemplates, } from '../kernel/backendShape.js';
|
|
11
|
+
import { declarationsWithComments, environmentSecrets, findBundleLeaks } from './bundleAudit.js';
|
|
12
|
+
import { KERNEL_CHANGELOG, readChangelog } from './changelogs.js';
|
|
13
|
+
import { assertInsideRepository } from './repository.js';
|
|
14
|
+
import { SDK_TARBALL } from './pluginWorkspaceTemplates.js';
|
|
15
|
+
import { stageExamples } from './exampleSources.js';
|
|
16
|
+
import { packageCustomIndexTs, packageCustomTsconfig, packageFirebaseJson, packageFunctionsIndexJs, packageFunctionsPackageJson, } from './packageTemplates.js';
|
|
17
|
+
/**
|
|
18
|
+
* `dist` é um modo do Vite para o qual NÃO existe `.env.dist`. É isso que garante um bundle sem
|
|
19
|
+
* projeto embutido: o repositório não tem `.env` de raiz servindo de fallback, então nada é inlinado.
|
|
20
|
+
*/
|
|
21
|
+
const DISTRIBUTION_TARGET = 'dist';
|
|
22
|
+
/**
|
|
23
|
+
* As exigências de backend das extensões de PRIMEIRA PARTE saem dos `extension-templates/*.json`, que
|
|
24
|
+
* são gerados dos `.ts` e conferidos pelo `verify-extensions` que o gate de qualidade acima já roda.
|
|
25
|
+
* Ler o `.json` gerado em vez do `.ts` evita carregar o Vite aqui só para avaliar um módulo.
|
|
26
|
+
*/
|
|
27
|
+
const firstPartyClaims = async (root) => {
|
|
28
|
+
const dir = join(root, 'extension-templates');
|
|
29
|
+
const files = (await readdir(dir)).filter((file) => file.endsWith('.json'));
|
|
30
|
+
const templates = await Promise.all(files.map((file) => readJson(join(dir, file))));
|
|
31
|
+
return claimsFromTemplates(templates);
|
|
32
|
+
};
|
|
33
|
+
const readJson = async (path) => JSON.parse(await readFile(path, 'utf8'));
|
|
34
|
+
/**
|
|
35
|
+
* Os `defineString` e as callables estão espalhados pelos handlers, não num arquivo só — então a
|
|
36
|
+
* varredura é a árvore inteira de `functions/src`, uma vez, para os dois. Derivar daqui é o que faz
|
|
37
|
+
* um parâmetro novo (ou uma callable nova) aparecer sozinho no manifesto, em vez de depender de
|
|
38
|
+
* alguém lembrar de atualizar um template.
|
|
39
|
+
*/
|
|
40
|
+
const scanBackendSources = async (directory) => {
|
|
41
|
+
const parameters = new Map();
|
|
42
|
+
const callables = new Set();
|
|
43
|
+
const walk = async (current) => {
|
|
44
|
+
for (const entry of await readdir(current, { withFileTypes: true })) {
|
|
45
|
+
const path = join(current, entry.name);
|
|
46
|
+
if (entry.isDirectory()) {
|
|
47
|
+
await walk(path);
|
|
48
|
+
}
|
|
49
|
+
else if (entry.name.endsWith('.ts') && !entry.name.endsWith('.test.ts')) {
|
|
50
|
+
const source = await readFile(path, 'utf8');
|
|
51
|
+
for (const parameter of declaredParametersIn(source)) {
|
|
52
|
+
const previous = parameters.get(parameter.name);
|
|
53
|
+
// Declarado em dois lugares com defaults diferentes: vale o mais exigente.
|
|
54
|
+
if (previous === undefined || parameter.required)
|
|
55
|
+
parameters.set(parameter.name, parameter);
|
|
56
|
+
}
|
|
57
|
+
for (const name of callableFunctionNames(source))
|
|
58
|
+
callables.add(name);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
await walk(directory);
|
|
63
|
+
return {
|
|
64
|
+
parameters: [...parameters.values()].sort((left, right) => left.name.localeCompare(right.name)),
|
|
65
|
+
callables: [...callables].sort((left, right) => left.localeCompare(right)),
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* Põe o SDK de autoria no pacote: o compilado, os tipos da API curada, e as extensões de primeira
|
|
70
|
+
* parte como exemplo.
|
|
71
|
+
*
|
|
72
|
+
* O tarball vai com nome FIXO (`microteia-sdk.tgz`, sem versão) porque o `extensions/package.json` do
|
|
73
|
+
* escritório aponta para ele por caminho: com a versão no nome, todo upgrade exigiria editar aquele
|
|
74
|
+
* arquivo à mão, e quem esquecesse continuaria compilando contra o SDK antigo em silêncio.
|
|
75
|
+
*
|
|
76
|
+
* As três conferências do fim são do ARTEFATO, não do procedimento — mesma postura do `bundleAudit`:
|
|
77
|
+
* o que sai daqui é `.d.ts` da superfície curada, e um comentário esquecido nele levaria para todo
|
|
78
|
+
* escritório a narrativa interna de uma decisão nossa.
|
|
79
|
+
*/
|
|
80
|
+
const stageSdk = async (root, stageDir, version) => {
|
|
81
|
+
const sourceDir = join(root, 'sdk');
|
|
82
|
+
const targetDir = join(stageDir, 'sdk');
|
|
83
|
+
const manifest = await readJson(join(sourceDir, 'package.json'));
|
|
84
|
+
const kernelVersion = manifest.microteia?.kernelVersion;
|
|
85
|
+
if (manifest.version !== version || kernelVersion === undefined) {
|
|
86
|
+
throw new Error('sdk/package.json is stale — "npm run verify" should have rebuilt it.');
|
|
87
|
+
}
|
|
88
|
+
await mkdir(targetDir, { recursive: true });
|
|
89
|
+
await run('npm', ['pack', '--silent', '--pack-destination', targetDir], { cwd: sourceDir });
|
|
90
|
+
const packed = (await readdir(targetDir)).filter((file) => file.endsWith('.tgz'));
|
|
91
|
+
if (packed.length !== 1) {
|
|
92
|
+
throw new Error(`Expected exactly one SDK tarball, found ${packed.length}.`);
|
|
93
|
+
}
|
|
94
|
+
await rename(join(targetDir, packed[0]), join(targetDir, SDK_TARBALL));
|
|
95
|
+
await cp(join(sourceDir, 'types'), join(targetDir, 'types'), { recursive: true });
|
|
96
|
+
// O `.d.ts` da superfície curada sai SEM comentário: o JSDoc deste repositório é em português e
|
|
97
|
+
// narra decisões e incidentes internos. O que o autor lê é `types/` e o `AUTHORING.md`, escritos
|
|
98
|
+
// para ele — e por isso `types/` fica de fora desta conferência, de propósito.
|
|
99
|
+
const documented = await declarationsWithComments(join(sourceDir, 'lib'));
|
|
100
|
+
if (documented.length > 0) {
|
|
101
|
+
throw new Error('Declarations in the SDK carry comments, which would ship internal notes to every office:\n'
|
|
102
|
+
+ documented.map((file) => ` ${relative(sourceDir, file)}`).join('\n')
|
|
103
|
+
+ '\n"removeComments" must stay on in tsconfig.sdk.json.');
|
|
104
|
+
}
|
|
105
|
+
// As extensões de primeira parte como material de autoria, em FONTE e uma pasta por extensão. O
|
|
106
|
+
// `.json` é o artefato e não ensina como se chega nele; a fonte ensina, e já viajava de qualquer
|
|
107
|
+
// forma — o código das views está dentro do `.json`, em string. `exampleSources.test.ts` compila cada
|
|
108
|
+
// uma e exige o `.json` versionado byte a byte.
|
|
109
|
+
const examples = await stageExamples(root, join(targetDir, 'examples'));
|
|
110
|
+
info(` ${examples.length} first-party extension(s) staged as source examples`);
|
|
111
|
+
return { version, kernelVersion, path: `sdk/${SDK_TARBALL}` };
|
|
112
|
+
};
|
|
113
|
+
export const pack = async (args) => {
|
|
114
|
+
await assertInsideRepository('pack');
|
|
115
|
+
const root = repoRoot;
|
|
116
|
+
const skipVerify = hasFlag(args, 'skip-verify');
|
|
117
|
+
const pkg = await readJson(join(root, 'package.json'));
|
|
118
|
+
const version = pkg.version;
|
|
119
|
+
/**
|
|
120
|
+
* O histórico técnico é conferido AQUI, antes de qualquer build. Uma entrada que falta é um minuto de
|
|
121
|
+
* conserto; descobri-la depois do `verify` e dos três builds custa dez, e é assim que a conferência
|
|
122
|
+
* passa a ser contornada com `--skip-verify`.
|
|
123
|
+
*/
|
|
124
|
+
const changelog = await readChangelog(root, KERNEL_CHANGELOG, version);
|
|
125
|
+
const kernelVersion = parseKernelVersion(await readFile(join(root, 'src/domain/schema/plugin/kernelVersion.ts'), 'utf8'));
|
|
126
|
+
const functionNames = exportedFunctionNames(await readFile(join(root, 'functions/src/index.ts'), 'utf8'));
|
|
127
|
+
const scan = await scanBackendSources(join(root, 'functions/src'));
|
|
128
|
+
const backendParameters = scan.parameters;
|
|
129
|
+
// Uma callable que não está exportada no `index.ts` não é deployada, e verificá-la acusaria uma
|
|
130
|
+
// ausência que é só do parser.
|
|
131
|
+
const callables = scan.callables.filter((name) => functionNames.includes(name));
|
|
132
|
+
const rootIndexes = await readJson(join(root, 'firestore.indexes.json'));
|
|
133
|
+
const claims = await firstPartyClaims(root);
|
|
134
|
+
const problems = claimProblems(claims, functionNames, rootIndexes.indexes);
|
|
135
|
+
if (problems.length > 0) {
|
|
136
|
+
throw new Error('An extension declares backend artifacts that do not add up, so the package would be wrong:\n'
|
|
137
|
+
+ problems.map((problem) => ` ${problem}`).join('\n'));
|
|
138
|
+
}
|
|
139
|
+
const baselineFunctions = baselineFunctionsOf(functionNames, claims);
|
|
140
|
+
const baselineIndexes = baselineIndexesOf(rootIndexes.indexes, claims);
|
|
141
|
+
const outputDir = flagValue(args, 'output') ?? join(root, 'distributions', 'kernel', version);
|
|
142
|
+
const stageDir = join(outputDir, 'package');
|
|
143
|
+
const tarball = join(outputDir, kernelTarballName(version));
|
|
144
|
+
heading(`Packaging Microteia kernel ${version} (contract ${kernelVersion})`);
|
|
145
|
+
const total = 7;
|
|
146
|
+
if (skipVerify) {
|
|
147
|
+
info('Quality gate skipped (--skip-verify).');
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
step(1, total, 'Quality gate');
|
|
151
|
+
await run('npm', ['run', 'verify'], { cwd: root });
|
|
152
|
+
}
|
|
153
|
+
step(2, total, `Building the portable frontend (TARGET=${DISTRIBUTION_TARGET})`);
|
|
154
|
+
await run('npm', ['run', 'build'], { cwd: root, env: { TARGET: DISTRIBUTION_TARGET } });
|
|
155
|
+
step(3, total, 'Compiling the Cloud Functions');
|
|
156
|
+
await run('npm', ['run', 'build:functions'], { cwd: root });
|
|
157
|
+
// Depois do `verify`, que já compilou o SDK — mas o `--skip-verify` existe, e um pacote sem SDK
|
|
158
|
+
// seria descoberto só no `plugin-init` de um escritório.
|
|
159
|
+
step(4, total, 'Building the authoring SDK');
|
|
160
|
+
await run('npm', ['run', 'build:host-types'], { cwd: root });
|
|
161
|
+
await run('npm', ['run', 'build:sdk'], { cwd: root });
|
|
162
|
+
step(5, total, 'Checking that the bundle carries no Firebase project');
|
|
163
|
+
const leaks = await findBundleLeaks(join(root, 'dist'), await environmentSecrets(root));
|
|
164
|
+
if (leaks.length > 0) {
|
|
165
|
+
throw new Error('The built frontend contains Firebase credentials, so it is not distributable.\n'
|
|
166
|
+
+ leaks.map((leak) => ` ${leak.file}: ${leak.what}`).join('\n')
|
|
167
|
+
+ `\nThe distribution build must run with TARGET=${DISTRIBUTION_TARGET}, for which no env file exists.`);
|
|
168
|
+
}
|
|
169
|
+
success('no project baked into the bundle');
|
|
170
|
+
step(6, total, 'Assembling the distribution');
|
|
171
|
+
await rm(stageDir, { recursive: true, force: true });
|
|
172
|
+
await mkdir(stageDir, { recursive: true });
|
|
173
|
+
const repoFirebase = await readJson(join(root, 'firebase.json'));
|
|
174
|
+
if (repoFirebase.hosting === undefined)
|
|
175
|
+
throw new Error('firebase.json has no hosting section.');
|
|
176
|
+
const repoFunctions = await readJson(join(root, 'functions/package.json'));
|
|
177
|
+
// `.DS_Store` e afins vêm de `public/` e entram no `dist` pela cópia literal que o Vite faz. O
|
|
178
|
+
// hosting já os ignoraria no upload, mas eles não têm por que existir dentro do pacote.
|
|
179
|
+
await cp(join(root, 'dist'), join(stageDir, 'hosting'), {
|
|
180
|
+
recursive: true,
|
|
181
|
+
filter: (source) => !basename(source).startsWith('.'),
|
|
182
|
+
});
|
|
183
|
+
// Os `.js.map` ficam de fora: sem o `src/` que eles apontam são inúteis para quem instala, e
|
|
184
|
+
// publicá-los entregaria a árvore interna de módulos do kernel — o desenho, ainda que não o
|
|
185
|
+
// código. (`sourcesContent` não é emitido, então o TypeScript em si nunca esteve neles.)
|
|
186
|
+
await cp(join(root, 'functions/lib'), join(stageDir, 'functions/lib'), {
|
|
187
|
+
recursive: true,
|
|
188
|
+
filter: (source) => !source.endsWith('.map'),
|
|
189
|
+
});
|
|
190
|
+
await cp(join(root, 'functions/package-lock.json'), join(stageDir, 'functions/package-lock.json'));
|
|
191
|
+
// O `.env.example` NÃO viaja. Dentro de `install/functions/` ele era uma armadilha: convidava a
|
|
192
|
+
// preencher a configuração ali, num diretório que o deploy seguinte apaga por inteiro. O que a
|
|
193
|
+
// instalação recebe é o `.env.<projectId>` na RAIZ, escrito a partir do manifesto e já comentado —
|
|
194
|
+
// um modelo a menos é um lugar errado a menos.
|
|
195
|
+
for (const file of ['firestore.rules', 'storage.rules']) {
|
|
196
|
+
await cp(join(root, file), join(stageDir, file));
|
|
197
|
+
}
|
|
198
|
+
// O histórico do kernel viaja DENTRO do pacote, e é de lá que o `unpack` o copia para a raiz da
|
|
199
|
+
// instalação. Escrito do conteúdo já conferido, para não ler o arquivo duas vezes.
|
|
200
|
+
await writeFile(join(stageDir, KERNEL_CHANGELOG), changelog);
|
|
201
|
+
// O `firestore.indexes.json` do pacote é ESCRITO, não copiado: a raiz é o conjunto completo (é o que
|
|
202
|
+
// roda em `microteia-dev` e `curatino`), e o que uma extensão reivindica sai daqui para ser criado
|
|
203
|
+
// pelo `provision` quando ela for instalada. Os `fieldOverrides` são todos do kernel e vão inteiros.
|
|
204
|
+
await writeFile(join(stageDir, 'firestore.indexes.json'), `${JSON.stringify({ ...rootIndexes, indexes: baselineIndexes }, null, 2)}\n`);
|
|
205
|
+
await mkdir(join(stageDir, 'functions/custom/src'), { recursive: true });
|
|
206
|
+
await writeFile(join(stageDir, 'firebase.json'), packageFirebaseJson(repoFirebase.hosting));
|
|
207
|
+
await writeFile(join(stageDir, 'functions/package.json'), packageFunctionsPackageJson(repoFunctions, version));
|
|
208
|
+
await writeFile(join(stageDir, 'functions/index.js'), packageFunctionsIndexJs());
|
|
209
|
+
await writeFile(join(stageDir, 'functions/custom/tsconfig.json'), packageCustomTsconfig());
|
|
210
|
+
await writeFile(join(stageDir, 'functions/custom/src/index.ts'), packageCustomIndexTs());
|
|
211
|
+
const sdk = await stageSdk(root, stageDir, version);
|
|
212
|
+
const manifest = {
|
|
213
|
+
id: KERNEL_DISTRIBUTION_ID,
|
|
214
|
+
name: 'Microteia Kernel',
|
|
215
|
+
version,
|
|
216
|
+
kernelVersion,
|
|
217
|
+
minimumCliVersion: MINIMUM_CLI_VERSION,
|
|
218
|
+
packagedAt: new Date().toISOString(),
|
|
219
|
+
components: KERNEL_COMPONENTS,
|
|
220
|
+
requires: {
|
|
221
|
+
functionsRegion: DEFAULT_FUNCTIONS_REGION,
|
|
222
|
+
nodeVersion: REQUIRED_NODE_VERSION,
|
|
223
|
+
},
|
|
224
|
+
functions: functionNames,
|
|
225
|
+
baselineFunctions,
|
|
226
|
+
baselineIndexes,
|
|
227
|
+
callables,
|
|
228
|
+
backendParameters,
|
|
229
|
+
manualPrerequisites: MANUAL_PREREQUISITES,
|
|
230
|
+
sdk,
|
|
231
|
+
};
|
|
232
|
+
await writeFile(join(stageDir, 'manifest.json'), `${JSON.stringify(manifest, null, 2)}\n`);
|
|
233
|
+
step(7, total, 'Writing the tarball');
|
|
234
|
+
await run('tar', ['-czf', tarball, '-C', stageDir, '.'], { cwd: root });
|
|
235
|
+
await rm(stageDir, { recursive: true, force: true });
|
|
236
|
+
/**
|
|
237
|
+
* A segunda cópia do manifesto, FORA do tarball, para que a versão e os pré-requisitos possam ser
|
|
238
|
+
* lidos sem desempacotar nada — e agora também para que o que foi BAIXADO possa ser conferido.
|
|
239
|
+
*
|
|
240
|
+
* Ela deixou de ser o mesmo JSON da de dentro, e vem depois do `tar` por causa disso: o `sha256` é do
|
|
241
|
+
* arquivo que acabou de ser escrito, e a cópia de dentro dele não teria como carregá-lo. É a única
|
|
242
|
+
* diferença entre as duas, e está declarada no tipo.
|
|
243
|
+
*/
|
|
244
|
+
const digest = await digestOfFile(tarball);
|
|
245
|
+
const published = {
|
|
246
|
+
...manifest,
|
|
247
|
+
tarball: { name: basename(tarball), ...digest },
|
|
248
|
+
};
|
|
249
|
+
await writeFile(join(outputDir, 'manifest.json'), `${JSON.stringify(published, null, 2)}\n`);
|
|
250
|
+
blank();
|
|
251
|
+
info(`Kernel ${version} packaged.`);
|
|
252
|
+
bullets([
|
|
253
|
+
`tarball: ${tarball}`,
|
|
254
|
+
`manifest: ${join(outputDir, 'manifest.json')}`,
|
|
255
|
+
`functions: ${functionNames.length} packaged, ${baselineFunctions.length} in the baseline`,
|
|
256
|
+
`callables: ${callables.length}`,
|
|
257
|
+
`claimed by extensions: ${functionNames.length - baselineFunctions.length} function(s), `
|
|
258
|
+
+ `${rootIndexes.indexes.length - baselineIndexes.length} index(es), from ${claims.length} extension(s)`,
|
|
259
|
+
`backend parameters: ${backendParameters.length}`,
|
|
260
|
+
`authoring SDK: ${sdk.version} (kernel contract ${sdk.kernelVersion})`,
|
|
261
|
+
`size: ${(digest.bytes / 1_000_000).toFixed(1)} MB, sha256 ${digest.sha256.slice(0, 12)}…`,
|
|
262
|
+
]);
|
|
263
|
+
blank();
|
|
264
|
+
info('Publish it with:');
|
|
265
|
+
bullets(['microteia publish --dry-run (says what would go up)', 'microteia publish']);
|
|
266
|
+
blank();
|
|
267
|
+
info('Or install this file directly, without publishing:');
|
|
268
|
+
bullets([
|
|
269
|
+
'microteia init --name <office>',
|
|
270
|
+
'microteia connect --project <firebase-project-id>',
|
|
271
|
+
`microteia unpack --kernel ${tarball}`,
|
|
272
|
+
'microteia deploy',
|
|
273
|
+
'microteia plugin-init (optional: author extensions in TypeScript)',
|
|
274
|
+
]);
|
|
275
|
+
blank();
|
|
276
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ParsedArgs } from '../shared/args.js';
|
|
2
|
+
/**
|
|
3
|
+
* O Console pronto para rodar em outra pasta — ou em outra máquina — sem o repositório.
|
|
4
|
+
*
|
|
5
|
+
* O que ele monta é pequeno de propósito: o `lib/` compilado, um `package.json` e um README. Não há
|
|
6
|
+
* dependência de npm a instalar porque o Console usa só módulos nativos do Node; o que ele exige são
|
|
7
|
+
* BINÁRIOS (`firebase`, `npm`, `tar`, `gcloud`), e esses são da máquina, não do pacote.
|
|
8
|
+
*
|
|
9
|
+
* O `package.json` é a razão de este comando existir em vez de um `cp -R`: o compilado é ESM, e sem
|
|
10
|
+
* `type: module` o Node só o carrega por adivinhação de sintaxe — disponível a partir do 22.7 e
|
|
11
|
+
* ausente antes dele. Montar a pasta à mão significa esquecer disso e culpar a ferramenta.
|
|
12
|
+
*/
|
|
13
|
+
export declare const packConsole: (args: ParsedArgs) => Promise<void>;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { access, chmod, cp, mkdir, rm, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { flagValue } from '../shared/args.js';
|
|
4
|
+
import { CLI_VERSION, consoleRoot, repoRoot } from '../shared/paths.js';
|
|
5
|
+
import { blank, bullets, heading, info, step, success } from '../shared/ui.js';
|
|
6
|
+
import { CONSOLE_CHANGELOG, readChangelog } from './changelogs.js';
|
|
7
|
+
import { consolePackageJson, consoleReadme } from './packageTemplates.js';
|
|
8
|
+
import { assertInsideRepository } from './repository.js';
|
|
9
|
+
/**
|
|
10
|
+
* O Console pronto para rodar em outra pasta — ou em outra máquina — sem o repositório.
|
|
11
|
+
*
|
|
12
|
+
* O que ele monta é pequeno de propósito: o `lib/` compilado, um `package.json` e um README. Não há
|
|
13
|
+
* dependência de npm a instalar porque o Console usa só módulos nativos do Node; o que ele exige são
|
|
14
|
+
* BINÁRIOS (`firebase`, `npm`, `tar`, `gcloud`), e esses são da máquina, não do pacote.
|
|
15
|
+
*
|
|
16
|
+
* O `package.json` é a razão de este comando existir em vez de um `cp -R`: o compilado é ESM, e sem
|
|
17
|
+
* `type: module` o Node só o carrega por adivinhação de sintaxe — disponível a partir do 22.7 e
|
|
18
|
+
* ausente antes dele. Montar a pasta à mão significa esquecer disso e culpar a ferramenta.
|
|
19
|
+
*/
|
|
20
|
+
export const packConsole = async (args) => {
|
|
21
|
+
await assertInsideRepository('pack-console');
|
|
22
|
+
const compiled = join(repoRoot, 'cli', 'lib');
|
|
23
|
+
const outputDir = flagValue(args, 'output')
|
|
24
|
+
?? join(repoRoot, 'distributions', 'console', CLI_VERSION);
|
|
25
|
+
heading(`Packaging Microteia Console ${CLI_VERSION}`);
|
|
26
|
+
const total = 3;
|
|
27
|
+
step(1, total, 'Checking the compiled Console');
|
|
28
|
+
try {
|
|
29
|
+
await access(join(compiled, 'index.js'));
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
throw new Error(`${compiled} has no compiled Console. Run "npm run build:cli" first `
|
|
33
|
+
+ '(or use "npm run pack:console", which does it).');
|
|
34
|
+
}
|
|
35
|
+
success(`${compiled}/index.js`);
|
|
36
|
+
/**
|
|
37
|
+
* O histórico do Console viaja COM o Console, e não com o pacote do kernel: é o único jeito de ele não
|
|
38
|
+
* poder descrever uma versão que não está ali. A conferência vem antes de montar a pasta, porque uma
|
|
39
|
+
* entrada que falta se escreve em um minuto e nada mais depende dela.
|
|
40
|
+
*/
|
|
41
|
+
step(2, total, 'Checking the changelog');
|
|
42
|
+
const changelog = await readChangelog(consoleRoot, CONSOLE_CHANGELOG, CLI_VERSION);
|
|
43
|
+
success(`${CONSOLE_CHANGELOG} covers ${CLI_VERSION}`);
|
|
44
|
+
step(3, total, 'Assembling the folder');
|
|
45
|
+
await rm(outputDir, { recursive: true, force: true });
|
|
46
|
+
await mkdir(outputDir, { recursive: true });
|
|
47
|
+
await cp(compiled, join(outputDir, 'lib'), { recursive: true });
|
|
48
|
+
await writeFile(join(outputDir, 'package.json'), consolePackageJson(CLI_VERSION));
|
|
49
|
+
await writeFile(join(outputDir, 'README.md'), consoleReadme(CLI_VERSION));
|
|
50
|
+
await writeFile(join(outputDir, CONSOLE_CHANGELOG), changelog);
|
|
51
|
+
// Executável com o shebang que o entrypoint já tem: é o que permite apontar um link para ele em
|
|
52
|
+
// qualquer diretório do PATH, sem npm e sem sudo. O `tsc` não carimba a permissão, e no repositório
|
|
53
|
+
// ela vem do `npm install` (que a aplica no alvo do `bin`) — o que não existe numa pasta copiada.
|
|
54
|
+
await chmod(join(outputDir, 'lib', 'index.js'), 0o755);
|
|
55
|
+
success(outputDir);
|
|
56
|
+
blank();
|
|
57
|
+
info('Publish it with:');
|
|
58
|
+
bullets(['microteia publish --console-only --dry-run', 'microteia publish --console-only']);
|
|
59
|
+
blank();
|
|
60
|
+
info('Or run this folder as it is, on any machine with Node 22 and the Firebase CLI:');
|
|
61
|
+
bullets([`node ${join(outputDir, 'lib', 'index.js')} --help`]);
|
|
62
|
+
blank();
|
|
63
|
+
};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* O que é GERADO dentro do pacote — o que difere de um workspace de deploy do repositório.
|
|
3
|
+
*
|
|
4
|
+
* O `firebase.json` do repositório não serve como está por duas razões: o `predeploy` dele compila o
|
|
5
|
+
* kernel (que no pacote já vem compilado, e cujo `src/` não viaja), e o hosting dele aponta para
|
|
6
|
+
* `dist`. Aqui o `predeploy` compila SÓ o que o escritório escreveu.
|
|
7
|
+
*/
|
|
8
|
+
export interface RepoFunctionsPackage {
|
|
9
|
+
dependencies?: Record<string, string>;
|
|
10
|
+
devDependencies?: Record<string, string>;
|
|
11
|
+
engines?: Record<string, string>;
|
|
12
|
+
}
|
|
13
|
+
export interface HostingConfig {
|
|
14
|
+
ignore: string[];
|
|
15
|
+
rewrites: unknown[];
|
|
16
|
+
headers: unknown[];
|
|
17
|
+
}
|
|
18
|
+
export declare const packageFirebaseJson: (hosting: HostingConfig) => string;
|
|
19
|
+
/**
|
|
20
|
+
* As dependências são copiadas INTACTAS do `functions/package.json` do repositório, para que o
|
|
21
|
+
* `package-lock.json` que viaja junto continue válido. O que muda é só o entrypoint (passa a ser o
|
|
22
|
+
* `index.js` que soma kernel e custom) e o `build`, que agora compila apenas `custom/`.
|
|
23
|
+
*/
|
|
24
|
+
/**
|
|
25
|
+
* A `version` não é enfeite: sem ela o npm não consegue formar `nome@versão` e todo aviso dele sobre
|
|
26
|
+
* este pacote sai com `package: undefined`, o que faz parecer que o arquivo está corrompido.
|
|
27
|
+
*
|
|
28
|
+
* `engines.node` vem do repositório e descreve o RUNTIME das Cloud Functions — é por ele que o Firebase
|
|
29
|
+
* escolhe em qual Node a function roda. Ele não descreve a máquina de quem instala, e é por isso que o
|
|
30
|
+
* npm avisa `EBADENGINE` quando as duas versões diferem: o aviso é esperado e não impede nada. Trocar
|
|
31
|
+
* o valor por uma faixa (`>=22`) calaria o aviso e passaria a deixar a escolha do runtime ambígua para
|
|
32
|
+
* o Firebase — o preço errado pela linha de saída.
|
|
33
|
+
*/
|
|
34
|
+
export declare const packageFunctionsPackageJson: (source: RepoFunctionsPackage, version: string) => string;
|
|
35
|
+
/**
|
|
36
|
+
* Entrypoint da instalação. O espalhamento mantém os nomes PLANOS (`onUserCreated`, e não
|
|
37
|
+
* `kernel-onUserCreated`), que é o que os deploys por nome e os gatilhos já existentes esperam.
|
|
38
|
+
*/
|
|
39
|
+
export declare const packageFunctionsIndexJs: () => string;
|
|
40
|
+
/**
|
|
41
|
+
* O `exclude` é cinto de segurança, não redundância: o `gatherCustomFunctions` já não copia teste para
|
|
42
|
+
* cá, mas ele reconhece as duas convenções usuais (`*.test.ts`, `__tests__/`) e um arquivo fora delas
|
|
43
|
+
* chegaria. Aqui ele chega e não compila — o que é um upload maior, e não um deploy quebrado.
|
|
44
|
+
*/
|
|
45
|
+
export declare const packageCustomTsconfig: () => string;
|
|
46
|
+
export declare const packageCustomIndexTs: () => string;
|
|
47
|
+
export declare const CONSOLE_PACKAGE_NAME = "@microteia/console";
|
|
48
|
+
/**
|
|
49
|
+
* O Console empacotado para rodar FORA do repositório — e agora publicável.
|
|
50
|
+
*
|
|
51
|
+
* O `type: module` não é detalhe: o compilado é ESM, e sem esta declaração o Node só o carrega por
|
|
52
|
+
* adivinhação de sintaxe — que existe a partir do 22.7 e falha em silêncio nas versões anteriores, com
|
|
53
|
+
* "Cannot use import statement outside a module". O `bin` é o que dá o comando `microteia` global.
|
|
54
|
+
*
|
|
55
|
+
* Ele deixou de ser `private`, e isso resolve um ovo-e-galinha: enquanto o Console também tinha de ser
|
|
56
|
+
* baixado de algum lugar, alguém precisava baixar o baixador — e o primeiro passo de quem instala era
|
|
57
|
+
* uma pasta recebida por e-mail e um `ln -s` escrito à mão. Publicado, o registry já dá URL versionada,
|
|
58
|
+
* impressão digital no lock, CDN e `npm outdated`, que era tudo o que o canal precisaria reimplementar.
|
|
59
|
+
*
|
|
60
|
+
* `files` é a lista exata, e o `CONSOLE-VERSIONS.md` está nela por um motivo que não é documentação: o
|
|
61
|
+
* `unpack` lê aquele arquivo AO LADO do binário que está rodando para pô-lo na raiz da instalação. Fora
|
|
62
|
+
* de `files`, ele não existe numa instalação global, e o comando passa a avisar que o Console não carrega
|
|
63
|
+
* histórico — na máquina do escritório, e só lá.
|
|
64
|
+
*/
|
|
65
|
+
export declare const consolePackageJson: (version: string) => string;
|
|
66
|
+
export declare const consoleReadme: (version: string) => string;
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* O que é GERADO dentro do pacote — o que difere de um workspace de deploy do repositório.
|
|
3
|
+
*
|
|
4
|
+
* O `firebase.json` do repositório não serve como está por duas razões: o `predeploy` dele compila o
|
|
5
|
+
* kernel (que no pacote já vem compilado, e cujo `src/` não viaja), e o hosting dele aponta para
|
|
6
|
+
* `dist`. Aqui o `predeploy` compila SÓ o que o escritório escreveu.
|
|
7
|
+
*/
|
|
8
|
+
export const packageFirebaseJson = (hosting) => JSON.stringify({
|
|
9
|
+
firestore: {
|
|
10
|
+
rules: 'firestore.rules',
|
|
11
|
+
indexes: 'firestore.indexes.json',
|
|
12
|
+
},
|
|
13
|
+
storage: {
|
|
14
|
+
rules: 'storage.rules',
|
|
15
|
+
},
|
|
16
|
+
functions: {
|
|
17
|
+
source: 'functions',
|
|
18
|
+
predeploy: ['npm --prefix "$RESOURCE_DIR" run build'],
|
|
19
|
+
},
|
|
20
|
+
hosting: {
|
|
21
|
+
public: 'hosting',
|
|
22
|
+
ignore: hosting.ignore,
|
|
23
|
+
rewrites: hosting.rewrites,
|
|
24
|
+
headers: hosting.headers,
|
|
25
|
+
},
|
|
26
|
+
}, null, 2) + '\n';
|
|
27
|
+
/**
|
|
28
|
+
* As dependências são copiadas INTACTAS do `functions/package.json` do repositório, para que o
|
|
29
|
+
* `package-lock.json` que viaja junto continue válido. O que muda é só o entrypoint (passa a ser o
|
|
30
|
+
* `index.js` que soma kernel e custom) e o `build`, que agora compila apenas `custom/`.
|
|
31
|
+
*/
|
|
32
|
+
/**
|
|
33
|
+
* A `version` não é enfeite: sem ela o npm não consegue formar `nome@versão` e todo aviso dele sobre
|
|
34
|
+
* este pacote sai com `package: undefined`, o que faz parecer que o arquivo está corrompido.
|
|
35
|
+
*
|
|
36
|
+
* `engines.node` vem do repositório e descreve o RUNTIME das Cloud Functions — é por ele que o Firebase
|
|
37
|
+
* escolhe em qual Node a function roda. Ele não descreve a máquina de quem instala, e é por isso que o
|
|
38
|
+
* npm avisa `EBADENGINE` quando as duas versões diferem: o aviso é esperado e não impede nada. Trocar
|
|
39
|
+
* o valor por uma faixa (`>=22`) calaria o aviso e passaria a deixar a escolha do runtime ambígua para
|
|
40
|
+
* o Firebase — o preço errado pela linha de saída.
|
|
41
|
+
*/
|
|
42
|
+
export const packageFunctionsPackageJson = (source, version) => JSON.stringify({
|
|
43
|
+
name: 'microteia-functions',
|
|
44
|
+
version,
|
|
45
|
+
private: true,
|
|
46
|
+
main: 'index.js',
|
|
47
|
+
engines: source.engines ?? { node: '22' },
|
|
48
|
+
scripts: {
|
|
49
|
+
build: 'tsc -p custom/tsconfig.json',
|
|
50
|
+
},
|
|
51
|
+
dependencies: source.dependencies ?? {},
|
|
52
|
+
devDependencies: source.devDependencies ?? {},
|
|
53
|
+
}, null, 2) + '\n';
|
|
54
|
+
/**
|
|
55
|
+
* Entrypoint da instalação. O espalhamento mantém os nomes PLANOS (`onUserCreated`, e não
|
|
56
|
+
* `kernel-onUserCreated`), que é o que os deploys por nome e os gatilhos já existentes esperam.
|
|
57
|
+
*/
|
|
58
|
+
export const packageFunctionsIndexJs = () => `// Generated by "microteia pack". Do not edit.
|
|
59
|
+
//
|
|
60
|
+
// The deployed function set is the compiled kernel plus whatever this installation added under
|
|
61
|
+
// custom/. Kernel functions cannot be overridden here: custom/ is spread last, so a name collision
|
|
62
|
+
// would silently replace a kernel trigger — keep your function names distinct.
|
|
63
|
+
const kernel = require('./lib/index.js');
|
|
64
|
+
const custom = require('./custom/lib/index.js');
|
|
65
|
+
|
|
66
|
+
module.exports = { ...kernel, ...custom };
|
|
67
|
+
`;
|
|
68
|
+
/**
|
|
69
|
+
* O `exclude` é cinto de segurança, não redundância: o `gatherCustomFunctions` já não copia teste para
|
|
70
|
+
* cá, mas ele reconhece as duas convenções usuais (`*.test.ts`, `__tests__/`) e um arquivo fora delas
|
|
71
|
+
* chegaria. Aqui ele chega e não compila — o que é um upload maior, e não um deploy quebrado.
|
|
72
|
+
*/
|
|
73
|
+
export const packageCustomTsconfig = () => JSON.stringify({
|
|
74
|
+
compilerOptions: {
|
|
75
|
+
module: 'commonjs',
|
|
76
|
+
moduleResolution: 'node',
|
|
77
|
+
target: 'es2022',
|
|
78
|
+
lib: ['ES2022'],
|
|
79
|
+
types: ['node'],
|
|
80
|
+
rootDir: 'src',
|
|
81
|
+
outDir: 'lib',
|
|
82
|
+
strict: true,
|
|
83
|
+
esModuleInterop: true,
|
|
84
|
+
skipLibCheck: true,
|
|
85
|
+
sourceMap: true,
|
|
86
|
+
noImplicitReturns: true,
|
|
87
|
+
},
|
|
88
|
+
include: ['src'],
|
|
89
|
+
exclude: ['**/*.test.ts', '**/*.test.tsx', '**/*.spec.ts', '**/*.spec.tsx', '**/__tests__/**'],
|
|
90
|
+
}, null, 2) + '\n';
|
|
91
|
+
export const packageCustomIndexTs = () => `// Cloud Functions belonging to this installation.
|
|
92
|
+
//
|
|
93
|
+
// Everything exported from this file is deployed alongside the Microteia kernel and survives a
|
|
94
|
+
// kernel upgrade — "microteia deploy" replaces lib/ but never touches custom/.
|
|
95
|
+
//
|
|
96
|
+
// Functions must be pinned to the same region as the rest of the installation, otherwise Firestore
|
|
97
|
+
// triggers will not fire. Example:
|
|
98
|
+
//
|
|
99
|
+
// import { onCall } from 'firebase-functions/v2/https';
|
|
100
|
+
//
|
|
101
|
+
// export const helloOffice = onCall({ region: 'southamerica-east1', cors: true }, () => {
|
|
102
|
+
// return { ok: true };
|
|
103
|
+
// });
|
|
104
|
+
|
|
105
|
+
export {};
|
|
106
|
+
`;
|
|
107
|
+
export const CONSOLE_PACKAGE_NAME = '@microteia/console';
|
|
108
|
+
/**
|
|
109
|
+
* O Console empacotado para rodar FORA do repositório — e agora publicável.
|
|
110
|
+
*
|
|
111
|
+
* O `type: module` não é detalhe: o compilado é ESM, e sem esta declaração o Node só o carrega por
|
|
112
|
+
* adivinhação de sintaxe — que existe a partir do 22.7 e falha em silêncio nas versões anteriores, com
|
|
113
|
+
* "Cannot use import statement outside a module". O `bin` é o que dá o comando `microteia` global.
|
|
114
|
+
*
|
|
115
|
+
* Ele deixou de ser `private`, e isso resolve um ovo-e-galinha: enquanto o Console também tinha de ser
|
|
116
|
+
* baixado de algum lugar, alguém precisava baixar o baixador — e o primeiro passo de quem instala era
|
|
117
|
+
* uma pasta recebida por e-mail e um `ln -s` escrito à mão. Publicado, o registry já dá URL versionada,
|
|
118
|
+
* impressão digital no lock, CDN e `npm outdated`, que era tudo o que o canal precisaria reimplementar.
|
|
119
|
+
*
|
|
120
|
+
* `files` é a lista exata, e o `CONSOLE-VERSIONS.md` está nela por um motivo que não é documentação: o
|
|
121
|
+
* `unpack` lê aquele arquivo AO LADO do binário que está rodando para pô-lo na raiz da instalação. Fora
|
|
122
|
+
* de `files`, ele não existe numa instalação global, e o comando passa a avisar que o Console não carrega
|
|
123
|
+
* histórico — na máquina do escritório, e só lá.
|
|
124
|
+
*/
|
|
125
|
+
export const consolePackageJson = (version) => JSON.stringify({
|
|
126
|
+
name: CONSOLE_PACKAGE_NAME,
|
|
127
|
+
version,
|
|
128
|
+
description: 'Install and update Microteia in a Firebase project you own.',
|
|
129
|
+
license: 'UNLICENSED',
|
|
130
|
+
type: 'module',
|
|
131
|
+
bin: { microteia: 'lib/index.js' },
|
|
132
|
+
files: ['lib', 'README.md', 'CONSOLE-VERSIONS.md'],
|
|
133
|
+
engines: { node: '>=22' },
|
|
134
|
+
publishConfig: { access: 'public' },
|
|
135
|
+
}, null, 2) + '\n';
|
|
136
|
+
export const consoleReadme = (version) => `# Microteia Console ${version}
|
|
137
|
+
|
|
138
|
+
Installs and updates Microteia in a Firebase project you own. It has no npm dependencies of its own —
|
|
139
|
+
what it needs are command-line tools that are already on the machine, listed at the bottom.
|
|
140
|
+
|
|
141
|
+
## Installing it
|
|
142
|
+
|
|
143
|
+
npm i -g ${CONSOLE_PACKAGE_NAME}
|
|
144
|
+
microteia --help
|
|
145
|
+
|
|
146
|
+
Or run it without installing anything:
|
|
147
|
+
|
|
148
|
+
npx ${CONSOLE_PACKAGE_NAME} --help
|
|
149
|
+
|
|
150
|
+
Where npm's global prefix belongs to root — Node installed system-wide under \`/usr/local\` — the global
|
|
151
|
+
install fails with EACCES. Point npm at a prefix of your own instead of reaching for sudo, which would
|
|
152
|
+
write root-owned files that then need sudo to remove:
|
|
153
|
+
|
|
154
|
+
npm config set prefix ~/.npm-global
|
|
155
|
+
export PATH="$HOME/.npm-global/bin:$PATH" # add to ~/.zshrc
|
|
156
|
+
|
|
157
|
+
This folder also runs as it is, with no npm at all:
|
|
158
|
+
|
|
159
|
+
node lib/index.js --help
|
|
160
|
+
|
|
161
|
+
## Using it
|
|
162
|
+
|
|
163
|
+
microteia init --name "<office>"
|
|
164
|
+
microteia connect --project <your-firebase-project-id>
|
|
165
|
+
microteia unpack --version latest
|
|
166
|
+
microteia deploy
|
|
167
|
+
|
|
168
|
+
\`connect\` prints everything that has to be prepared in the Firebase project first — start with the
|
|
169
|
+
Blaze plan, since nothing else can be created without it.
|
|
170
|
+
|
|
171
|
+
\`unpack --version\` reads the published catalog, downloads the version and checks its sha256 before
|
|
172
|
+
touching what is installed. On a machine that cannot reach the catalog, name a file you already have:
|
|
173
|
+
|
|
174
|
+
microteia unpack --kernel <microteia-kernel-x.y.z>.tgz
|
|
175
|
+
|
|
176
|
+
\`microteia --version\` answers what is installed here, and says so when a newer kernel is published.
|
|
177
|
+
|
|
178
|
+
Later, whenever an office installs an extension that needs server-side resources, run:
|
|
179
|
+
|
|
180
|
+
microteia provision
|
|
181
|
+
|
|
182
|
+
The extension shows "Backend pending" in the application until you do, and stays out of the menu.
|
|
183
|
+
|
|
184
|
+
## What has to exist on this machine
|
|
185
|
+
|
|
186
|
+
| Tool | Used for |
|
|
187
|
+
| ------------- | -------------------------------------------------------------- |
|
|
188
|
+
| Node.js 22+ | running this Console (newer is fine; the functions' own runtime is pinned to 22) |
|
|
189
|
+
| \`firebase\` | every deploy — authenticate with \`firebase login\` first |
|
|
190
|
+
| \`npm\`, \`tar\` | installing the functions' dependencies and unpacking the kernel |
|
|
191
|
+
| \`gcloud\` | creating the App Engine application, and reading which extensions an office installed (\`gcloud auth login\`) |
|
|
192
|
+
|
|
193
|
+
The \`pack\` and \`publish\` commands in here build and release the platform itself, and only work inside
|
|
194
|
+
the Microteia repository.
|
|
195
|
+
|
|
196
|
+
## What changed in this Console
|
|
197
|
+
|
|
198
|
+
\`CONSOLE-VERSIONS.md\`, in this folder. \`unpack\` copies it into the installation it manages, beside the
|
|
199
|
+
platform's own \`KERNEL-VERSIONS.md\` — each history travels with the artifact it describes.
|
|
200
|
+
`;
|
|
@@ -0,0 +1,19 @@
|
|
|
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 declare 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 declare const workspacePackageJson: (officeName: string, sdkPath: string) => string;
|