@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.
Files changed (85) hide show
  1. package/CONSOLE-VERSIONS.md +85 -0
  2. package/README.md +64 -0
  3. package/lib/console/backendEnv.d.ts +52 -0
  4. package/lib/console/backendEnv.js +118 -0
  5. package/lib/console/backendIndexes.d.ts +40 -0
  6. package/lib/console/backendIndexes.js +178 -0
  7. package/lib/console/backendParameters.d.ts +48 -0
  8. package/lib/console/backendParameters.js +100 -0
  9. package/lib/console/callableAccess.d.ts +39 -0
  10. package/lib/console/callableAccess.js +61 -0
  11. package/lib/console/channel.d.ts +49 -0
  12. package/lib/console/channel.js +145 -0
  13. package/lib/console/connect.d.ts +2 -0
  14. package/lib/console/connect.js +74 -0
  15. package/lib/console/customFunctions.d.ts +120 -0
  16. package/lib/console/customFunctions.js +298 -0
  17. package/lib/console/deploy.d.ts +2 -0
  18. package/lib/console/deploy.js +261 -0
  19. package/lib/console/deployFunctions.d.ts +45 -0
  20. package/lib/console/deployFunctions.js +204 -0
  21. package/lib/console/environment.d.ts +62 -0
  22. package/lib/console/environment.js +151 -0
  23. package/lib/console/firebaseCli.d.ts +15 -0
  24. package/lib/console/firebaseCli.js +90 -0
  25. package/lib/console/firestoreRest.d.ts +39 -0
  26. package/lib/console/firestoreRest.js +131 -0
  27. package/lib/console/hostingCheck.d.ts +29 -0
  28. package/lib/console/hostingCheck.js +44 -0
  29. package/lib/console/init.d.ts +2 -0
  30. package/lib/console/init.js +60 -0
  31. package/lib/console/pluginWorkspace.d.ts +48 -0
  32. package/lib/console/pluginWorkspace.js +148 -0
  33. package/lib/console/provision.d.ts +70 -0
  34. package/lib/console/provision.js +478 -0
  35. package/lib/console/regionOrphans.d.ts +43 -0
  36. package/lib/console/regionOrphans.js +99 -0
  37. package/lib/console/runtimeConfigShape.d.ts +25 -0
  38. package/lib/console/runtimeConfigShape.js +35 -0
  39. package/lib/console/unpack.d.ts +9 -0
  40. package/lib/console/unpack.js +333 -0
  41. package/lib/console/versions.d.ts +10 -0
  42. package/lib/console/versions.js +72 -0
  43. package/lib/console/workspace.d.ts +19 -0
  44. package/lib/console/workspace.js +33 -0
  45. package/lib/index.d.ts +2 -0
  46. package/lib/index.js +136 -0
  47. package/lib/kernel/backendShape.d.ts +74 -0
  48. package/lib/kernel/backendShape.js +91 -0
  49. package/lib/kernel/channel.d.ts +79 -0
  50. package/lib/kernel/channel.js +157 -0
  51. package/lib/kernel/manifest.d.ts +138 -0
  52. package/lib/kernel/manifest.js +145 -0
  53. package/lib/shared/args.d.ts +14 -0
  54. package/lib/shared/args.js +44 -0
  55. package/lib/shared/digest.d.ts +30 -0
  56. package/lib/shared/digest.js +34 -0
  57. package/lib/shared/paths.d.ts +90 -0
  58. package/lib/shared/paths.js +97 -0
  59. package/lib/shared/run.d.ts +28 -0
  60. package/lib/shared/run.js +49 -0
  61. package/lib/shared/ui.d.ts +23 -0
  62. package/lib/shared/ui.js +43 -0
  63. package/lib/vendor/authoringGuide.d.ts +19 -0
  64. package/lib/vendor/authoringGuide.js +284 -0
  65. package/lib/vendor/bundleAudit.d.ts +19 -0
  66. package/lib/vendor/bundleAudit.js +95 -0
  67. package/lib/vendor/changelogs.d.ts +62 -0
  68. package/lib/vendor/changelogs.js +131 -0
  69. package/lib/vendor/exampleSources.d.ts +29 -0
  70. package/lib/vendor/exampleSources.js +126 -0
  71. package/lib/vendor/installationDocs.d.ts +35 -0
  72. package/lib/vendor/installationDocs.js +243 -0
  73. package/lib/vendor/pack.d.ts +2 -0
  74. package/lib/vendor/pack.js +276 -0
  75. package/lib/vendor/packConsole.d.ts +13 -0
  76. package/lib/vendor/packConsole.js +63 -0
  77. package/lib/vendor/packageTemplates.d.ts +66 -0
  78. package/lib/vendor/packageTemplates.js +200 -0
  79. package/lib/vendor/pluginWorkspaceTemplates.d.ts +19 -0
  80. package/lib/vendor/pluginWorkspaceTemplates.js +29 -0
  81. package/lib/vendor/publish.d.ts +2 -0
  82. package/lib/vendor/publish.js +277 -0
  83. package/lib/vendor/repository.d.ts +9 -0
  84. package/lib/vendor/repository.js +26 -0
  85. package/package.json +21 -0
@@ -0,0 +1,126 @@
1
+ import { mkdir, readFile, readdir, writeFile } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ /**
4
+ * As extensões de primeira parte, empacotadas como FONTE — `plugin.ts` e as views em `.tsx` —, uma pasta
5
+ * por extensão.
6
+ *
7
+ * Viajavam como `.json`. Um `.json` de 90 KB não ensina nada: é o artefato, e quem abre não vê como se
8
+ * chega nele. O que ensina é a fonte, e ela já viaja de qualquer forma — o código das views está dentro
9
+ * do `.json`, em string. Passar a mandar o `.ts` não expõe nada novo; expõe de forma legível o que já ia.
10
+ *
11
+ * A única transformação é de IMPORT: neste repositório um plugin importa `../../domain/entities/...` e
12
+ * `../contributionBuilders`; do lado do escritório, tudo isso é `@microteia/sdk`. Todo símbolo usado
13
+ * pelos doze está no barril do SDK — e é por isso que a conferência é possível: `exampleSources.test.ts`
14
+ * COMPILA cada exemplo reescrito e exige que o `.json` saia byte a byte igual ao versionado. Um símbolo
15
+ * que faltasse no barril reprovaria ali, e não no escritório de alguém.
16
+ */
17
+ /** Arquivo distribuído → módulo de origem. O nome da pasta do exemplo é o do `.json`, sem extensão. */
18
+ export const EXAMPLE_SOURCES = {
19
+ brasil: 'brasil.ts',
20
+ calendar: 'calendar.ts',
21
+ dashboard: 'dashboard.ts',
22
+ 'locale-pt-br': 'localePtBr',
23
+ news: 'news.ts',
24
+ };
25
+ /**
26
+ * Reescreve os imports de um plugin para a forma que o escritório usa.
27
+ *
28
+ * Um especificador relativo que alcance `domain/` ou os construtores de contribuição é, do lado de fora,
29
+ * `@microteia/sdk`. As views passam a ser vizinhas do `plugin.ts` (`./views/X`), porque no exemplo cada
30
+ * extensão tem a sua pasta — aqui elas moram num diretório comum, com um nível a mais.
31
+ */
32
+ export const rewriteImports = (source) => source.replace(/from '(\.[^']*)'/g, (match, specifier) => {
33
+ if (/(^|\/)contributionBuilders$/.test(specifier) || specifier.includes('domain/')) {
34
+ return "from '@microteia/sdk'";
35
+ }
36
+ // `./views/<plugin>/Nome.tsx?raw` -> `./views/Nome.tsx?raw`
37
+ const view = /^\.\/views\/[^/]+\/(.+)$/.exec(specifier);
38
+ return view === null ? match : `from './views/${view[1]}'`;
39
+ });
40
+ const HEADER = (id) => `// Example: a Microteia first-party extension, as SOURCE.
41
+ //
42
+ // This is the same code that produces ${id}.json — the artifact the platform installs. Build it with:
43
+ //
44
+ // npx microteia-plugin build ${id}/plugin.ts
45
+ //
46
+ // The only difference from how it is written inside Microteia is the import path: there it reaches into
47
+ // the kernel tree, here everything comes from '@microteia/sdk'.
48
+
49
+ `;
50
+ /**
51
+ * Os módulos VIZINHOS que o plugin importa — hoje, os catálogos de mensagem (`./newsMessages`,
52
+ * `./newsMessagesPtBr`). Um exemplo tem de viajar com o que ele importa, ou o `plugin.ts` staged não
53
+ * compila; enumerar os arquivos à mão numa lista aqui seria a mesma dívida que a lista de views era.
54
+ *
55
+ * A busca é transitiva porque um catálogo importa o outro (o de tradução lê o namespace do de origem),
56
+ * e é limitada ao diretório do marketplace: o que alcança `domain/` já virou `@microteia/sdk`.
57
+ */
58
+ const siblingModules = async (marketplace, entry) => {
59
+ const collected = new Map();
60
+ const pending = [entry];
61
+ while (pending.length > 0) {
62
+ const name = pending.shift();
63
+ const source = await readFile(join(marketplace, name), 'utf8');
64
+ for (const match of source.matchAll(/from '\.\/([A-Za-z][\w.-]*)'/g)) {
65
+ const file = `${match[1]}.ts`;
66
+ if (collected.has(file))
67
+ continue;
68
+ try {
69
+ collected.set(file, rewriteImports(await readFile(join(marketplace, file), 'utf8')));
70
+ }
71
+ catch {
72
+ continue;
73
+ }
74
+ pending.push(file);
75
+ }
76
+ }
77
+ return collected;
78
+ };
79
+ const viewFiles = async (viewsDir) => {
80
+ try {
81
+ return (await readdir(viewsDir)).filter((name) => name.endsWith('.tsx') || name.endsWith('.ts'));
82
+ }
83
+ catch {
84
+ return [];
85
+ }
86
+ };
87
+ /**
88
+ * Escreve `<target>/<plugin>/plugin.ts` e `<target>/<plugin>/views/*` para cada exemplo. Devolve os
89
+ * nomes escritos, que é o que o `pack` reporta.
90
+ */
91
+ export const stageExamples = async (repo, target) => {
92
+ const marketplace = join(repo, 'src/plugins/marketplace');
93
+ const written = [];
94
+ for (const [id, origin] of Object.entries(EXAMPLE_SOURCES)) {
95
+ const directory = join(target, id);
96
+ await mkdir(directory, { recursive: true });
97
+ if (origin.endsWith('.ts')) {
98
+ const source = await readFile(join(marketplace, origin), 'utf8');
99
+ await writeFile(join(directory, 'plugin.ts'), HEADER(id) + rewriteImports(source));
100
+ for (const [name, content] of await siblingModules(marketplace, origin)) {
101
+ await writeFile(join(directory, name), content);
102
+ }
103
+ const plugin = origin.replace(/\.ts$/, '');
104
+ const views = join(marketplace, 'views', plugin);
105
+ const files = await viewFiles(views);
106
+ if (files.length > 0)
107
+ await mkdir(join(directory, 'views'), { recursive: true });
108
+ for (const name of files) {
109
+ await writeFile(join(directory, 'views', name), await readFile(join(views, name), 'utf8'));
110
+ }
111
+ }
112
+ else {
113
+ // Extensão que é um DIRETÓRIO (o pacote de idioma, com um arquivo por namespace). O `index.ts`
114
+ // vira `plugin.ts`; os demais são vizinhos dele e os imports relativos seguem valendo.
115
+ for (const name of await readdir(join(marketplace, origin))) {
116
+ if (!name.endsWith('.ts') || name.endsWith('.test.ts'))
117
+ continue;
118
+ const source = rewriteImports(await readFile(join(marketplace, origin, name), 'utf8'));
119
+ const isEntry = name === 'index.ts';
120
+ await writeFile(join(directory, isEntry ? 'plugin.ts' : name), isEntry ? HEADER(id) + source : source);
121
+ }
122
+ }
123
+ written.push(id);
124
+ }
125
+ return written.sort();
126
+ };
@@ -0,0 +1,35 @@
1
+ import type { KernelManifest } from '../kernel/manifest.js';
2
+ /**
3
+ * Os dois documentos que ficam ao lado do `microteia.yaml`.
4
+ *
5
+ * Eram um `README.md` DENTRO do pacote, em `.microteia/install/`. Estava no lugar errado por duas razões:
6
+ * ninguém abre um diretório que se anuncia como descartável para ler documentação, e o que ele explicava
7
+ * — onde escrever function, onde ficam as configurações — apontava para caminhos de dentro dele mesmo,
8
+ * que é justamente o que não se deve editar.
9
+ *
10
+ * A divisão entre os dois é sobre QUEM ESCREVE:
11
+ *
12
+ * - `README.md` é do escritório. Nasce se não existir e nunca é reescrito — ele vai renomear coisas,
13
+ * acrescentar o contexto do negócio dele, apagar o que não usa. Por isso só contém o que não muda.
14
+ * - `MICROTEIA.md` é nosso. É SOBREPOSTO a cada `unpack`, e é onde vai o detalhe que acompanha a versão:
15
+ * a lista de comandos, os números do pacote, os caminhos. Um documento que promete estar atualizado
16
+ * não pode ser editável, e um documento que a pessoa edita não pode prometer isso.
17
+ *
18
+ * Ao lado deles ficam os dois históricos técnicos, que seguem a política do `MICROTEIA.md` e moram em
19
+ * `changelogs.ts` — cada um viaja no artefato que descreve, e não neste módulo.
20
+ */
21
+ export declare const INSTALLATION_README = "README.md";
22
+ export declare const INSTALLATION_GUIDE = "MICROTEIA.md";
23
+ /**
24
+ * O README do escritório. Escrito UMA vez, e daí em diante é dele.
25
+ *
26
+ * Deliberadamente sem número de versão, sem contagem de function e sem nada que envelheça: o que
27
+ * envelhece vive no `MICROTEIA.md`, que é reescrito. Um README com um dado velho ensina a desconfiar do
28
+ * arquivo inteiro.
29
+ */
30
+ export declare const installationReadme: (officeName: string) => string;
31
+ /**
32
+ * O documento técnico. SOBREPOSTO a cada `unpack`, e por isso é onde o detalhe que acompanha a versão
33
+ * pode viver — carimbado com os números do pacote que está instalado, não com uma cópia deles.
34
+ */
35
+ export declare const installationGuide: (officeName: string, manifest: KernelManifest, examples: string[]) => string;
@@ -0,0 +1,243 @@
1
+ /**
2
+ * Os dois documentos que ficam ao lado do `microteia.yaml`.
3
+ *
4
+ * Eram um `README.md` DENTRO do pacote, em `.microteia/install/`. Estava no lugar errado por duas razões:
5
+ * ninguém abre um diretório que se anuncia como descartável para ler documentação, e o que ele explicava
6
+ * — onde escrever function, onde ficam as configurações — apontava para caminhos de dentro dele mesmo,
7
+ * que é justamente o que não se deve editar.
8
+ *
9
+ * A divisão entre os dois é sobre QUEM ESCREVE:
10
+ *
11
+ * - `README.md` é do escritório. Nasce se não existir e nunca é reescrito — ele vai renomear coisas,
12
+ * acrescentar o contexto do negócio dele, apagar o que não usa. Por isso só contém o que não muda.
13
+ * - `MICROTEIA.md` é nosso. É SOBREPOSTO a cada `unpack`, e é onde vai o detalhe que acompanha a versão:
14
+ * a lista de comandos, os números do pacote, os caminhos. Um documento que promete estar atualizado
15
+ * não pode ser editável, e um documento que a pessoa edita não pode prometer isso.
16
+ *
17
+ * Ao lado deles ficam os dois históricos técnicos, que seguem a política do `MICROTEIA.md` e moram em
18
+ * `changelogs.ts` — cada um viaja no artefato que descreve, e não neste módulo.
19
+ */
20
+ export const INSTALLATION_README = 'README.md';
21
+ export const INSTALLATION_GUIDE = 'MICROTEIA.md';
22
+ /**
23
+ * O README do escritório. Escrito UMA vez, e daí em diante é dele.
24
+ *
25
+ * Deliberadamente sem número de versão, sem contagem de function e sem nada que envelheça: o que
26
+ * envelhece vive no `MICROTEIA.md`, que é reescrito. Um README com um dado velho ensina a desconfiar do
27
+ * arquivo inteiro.
28
+ */
29
+ export const installationReadme = (officeName) => `# ${officeName}
30
+
31
+ This directory is a **Microteia** installation: a multi-tenant business platform where the applications
32
+ are built by *declaration* — screens, automations, actions and pages arrive as extensions, and the
33
+ platform itself is never modified.
34
+
35
+ It is yours. Rename it, describe your business in it, delete what you do not use. Nothing rewrites this
36
+ file. The reference that has to stay current lives in **[MICROTEIA.md](./MICROTEIA.md)**, which is
37
+ replaced on every \`microteia unpack\` — read that one for commands, paths and version detail. Beside it,
38
+ **[KERNEL-VERSIONS.md](./KERNEL-VERSIONS.md)** and **[CONSOLE-VERSIONS.md](./CONSOLE-VERSIONS.md)** say
39
+ what changed in each version of the platform and of the Console.
40
+
41
+ ## The shape of this directory
42
+
43
+ microteia.yaml this installation: name, Firebase project, region, kernel version
44
+ .env.<projectId> your backend settings. Credentials — gitignored
45
+ KERNEL-VERSIONS.md what changed in each version of the platform
46
+ CONSOLE-VERSIONS.md what changed in each version of the Console that installs it
47
+ extensions/ the extensions you write
48
+ functions/ Cloud Functions shared by more than one extension
49
+ .microteia/ the unpacked platform. DISPOSABLE — nothing of yours lives here
50
+
51
+ The line that explains the rest: **nothing you write lives in \`.microteia/\`.** That directory is
52
+ replaced whole on every upgrade. Everything of yours sits beside this file.
53
+
54
+ ## Day to day
55
+
56
+ microteia unpack --version latest # take the newest published platform version
57
+ microteia deploy # publish it — or --only hosting, --only functions
58
+ microteia provision # apply what installed extensions need
59
+
60
+ \`unpack --version\` reads the published catalog, downloads the version and checks its sha256 before
61
+ touching what is installed here. On a machine that cannot reach the catalog, name a file instead:
62
+ \`microteia unpack --kernel <package>.tgz\`. And \`microteia --version\` says when a newer one is out.
63
+
64
+ ## Building your own extensions
65
+
66
+ An extension is a declaration the platform installs — a screen with its fields, an automation, a page.
67
+ You write it in TypeScript and a compiler produces the \`.json\` that gets installed:
68
+
69
+ cd extensions
70
+ npx microteia-plugin create # guided: asks what the extension should carry
71
+ npx microteia-plugin check <folder>/plugin.ts
72
+ npx microteia-plugin build <folder>/plugin.ts
73
+
74
+ \`extensions/examples/\` holds every extension that ships with Microteia, in source form — the best
75
+ reference there is. \`extensions/AUTHORING.md\` is the contract: extension points, the API a page may
76
+ use, translation rules, size limits.
77
+
78
+ ## Working with an AI assistant
79
+
80
+ \`extensions/\` registers an MCP server (\`.mcp.json\`), so an assistant in your editor can ask **this**
81
+ installation what it offers — the extension points it has, what a page may import, and whether what it
82
+ just wrote would be accepted — instead of guessing from documentation. \`extensions/AGENTS.md\` holds the
83
+ rules it should follow.
84
+
85
+ The point of that is not novelty: it is that the assistant's answer can be *checked* before anything is
86
+ installed, by the same validation the platform runs.
87
+ `;
88
+ const commandRows = () => [
89
+ '| Command | What it does |',
90
+ '|---|---|',
91
+ '| `microteia unpack --version <latest\\|x.y.z>` | Downloads a platform version, verifies it, and puts it in place. Touches no Firebase — safe any time |',
92
+ '| `microteia unpack --kernel <pkg>.tgz` | The same, from a file you already have — for a machine with no access to the catalog |',
93
+ '| `microteia deploy [--only …] [--prune]` | Publishes what is in place: `rules`, `indexes`, `functions`, `hosting`. `--prune` also deletes functions left behind in a region this version no longer uses |',
94
+ '| `microteia provision [--prune]` | Gives installed extensions the functions and indexes they ask for |',
95
+ '| `microteia connect --project <id>` | Binds this installation to a Firebase project you own |',
96
+ '| `microteia plugin-init` | Prepares `extensions/` for authoring in TypeScript |',
97
+ ].join('\n');
98
+ /**
99
+ * O documento técnico. SOBREPOSTO a cada `unpack`, e por isso é onde o detalhe que acompanha a versão
100
+ * pode viver — carimbado com os números do pacote que está instalado, não com uma cópia deles.
101
+ */
102
+ export const installationGuide = (officeName, manifest, examples) => {
103
+ const baseline = (manifest.baselineFunctions ?? manifest.functions).length;
104
+ const claimed = manifest.functions.length - baseline;
105
+ return `# Microteia — installation reference
106
+
107
+ > Generated by \`microteia unpack\`. **Replaced on every unpack** — do not edit it; put your own notes in
108
+ > [README.md](./README.md), which is never rewritten.
109
+
110
+ | | |
111
+ |---|---|
112
+ | Installation | ${officeName} |
113
+ | Platform version | ${manifest.version} |
114
+ | Extension contract | ${manifest.kernelVersion} |
115
+ | Console required | ${manifest.minimumCliVersion} or newer |
116
+ | Functions region | ${manifest.requires.functionsRegion} |
117
+ | Cloud Functions | ${baseline} baseline, ${claimed} claimed by extensions |
118
+ ${manifest.sdk === undefined ? '' : `| Authoring SDK | ${manifest.sdk.version} |\n`}
119
+ ## 1. What lives where, and why
120
+
121
+ microteia.yaml the installation record. Written by the commands; readable by you
122
+ .env.<projectId> YOUR backend settings — credentials
123
+ .gitignore covers the two above
124
+ README.md yours, never rewritten
125
+ MICROTEIA.md this file, replaced on every unpack
126
+ KERNEL-VERSIONS.md the platform's technical history, replaced on every unpack
127
+ CONSOLE-VERSIONS.md the Console's own, replaced on every unpack
128
+ extensions/ the extensions you write
129
+ <plugin>/plugin.ts the source of one extension
130
+ <plugin>/views/*.tsx its pages, as real type-checked files
131
+ <plugin>/functions/ its own Cloud Functions
132
+ <plugin>/<id>.json the built artifact — generated, do not hand-edit
133
+ examples/ every first-party extension, in source form
134
+ AUTHORING.md the authoring contract
135
+ functions/ Cloud Functions shared by more than one extension
136
+ .microteia/ DISPOSABLE
137
+ install/ the unpacked platform. Replaced whole on every unpack
138
+ firebase-config.json resolved from your Firebase project by \`connect\`
139
+
140
+ **Nothing you write belongs in \`.microteia/\`.** \`unpack\` deletes that directory and replaces it; only
141
+ \`functions/node_modules\` survives, and only because it is a cache. This is not a convention to respect —
142
+ it is what makes an upgrade trustworthy, and the reason your files are elsewhere.
143
+
144
+ ## 2. Commands
145
+
146
+ ${commandRows()}
147
+
148
+ \`unpack\` and \`deploy\` are separate so that taking a new version does not oblige you to publish
149
+ everything, and so that there is a moment between the two to fill in a setting the new version asks for.
150
+
151
+ Between the two, \`microteia.yaml\` says both: \`kernel.version\` is what is in place, \`kernel.deployed\`
152
+ is what the project runs. \`microteia --version\` prints them next to the Console's own. What changed between
153
+ two versions is in \`KERNEL-VERSIONS.md\` and \`CONSOLE-VERSIONS.md\`. Each is written by the artifact it
154
+ describes — the first travels inside the package, the second with the Console — which is what keeps
155
+ either from describing a version that is not installed here. Both are replaced on every unpack, so put
156
+ nothing of yours in them.
157
+
158
+ \`unpack\` replaces \`.microteia/install/\` whole, and a package carries only the platform's own composite
159
+ indexes — an index an extension asks for is not in it, so that it does not travel to installations that
160
+ never install that extension. So \`unpack\` puts back what this installation had already declared, from
161
+ \`backend.indexes\` in \`microteia.yaml\`. Without that, publishing indexes after an upgrade would find
162
+ indexes in the project that the file no longer declares, and **offer to delete them** — for extensions
163
+ that are merely turned off, and whose indexes are the reason their screens are fast.
164
+
165
+ An index of an extension you removed stays declared and is reported on every \`provision\`. It costs only
166
+ writes on the collection it covers. \`microteia provision --prune\` lets it go: it drops out of this
167
+ installation, and the next \`microteia deploy --only indexes\` offers to delete it from the project —
168
+ deliberately, because you asked.
169
+
170
+ ## 3. Backend settings
171
+
172
+ They live in \`.env.<projectId>\`, next to \`microteia.yaml\`. \`unpack\` creates the file and adds any
173
+ setting a new version introduces, **never overwriting what you filled in**.
174
+
175
+ After changing a value, run \`microteia provision\`. The value is stamped into each Cloud Function at
176
+ *its* deploy, so a function already running keeps the previous one until it is deployed again; provision
177
+ notices the change (by a salted digest in \`microteia.yaml\`) and requeues exactly the functions that
178
+ carry that setting.
179
+
180
+ An empty line means "not configured". A feature that needs it stays off rather than failing halfway.
181
+
182
+ ## 4. Your own Cloud Functions
183
+
184
+ Two places, answering two different questions:
185
+
186
+ | Where | When |
187
+ |---|---|
188
+ | \`extensions/<plugin>/functions/\` | the function belongs to that extension |
189
+ | \`functions/\` | the function is shared by more than one |
190
+
191
+ Each directory is read through its \`index.ts\` — export from there what should be deployed.
192
+ \`microteia deploy\` gathers them into the package, generates the entry point, and refuses the deploy if
193
+ two of them export the same name, or if one collides with a platform function. That refusal matters: the
194
+ entry point spreads yours *after* the platform's, so a repeated name would replace a platform trigger
195
+ silently, and a trigger that was replaced does not fail — it simply stops happening.
196
+
197
+ A function that belongs to an extension should also be declared in its
198
+ \`manifest.backend.functions\`. That is what makes the installation deploy it only where the extension is
199
+ installed, instead of everywhere.
200
+
201
+ Functions are pinned to **${manifest.requires.functionsRegion}**. One in another region receives no
202
+ Firestore trigger from this project, and the deploy reports nothing.
203
+
204
+ ## 5. Writing extensions
205
+
206
+ cd extensions
207
+ npx microteia-plugin create # guided
208
+ npx microteia-plugin create function # adds a Cloud Function to an existing extension
209
+ npx tsc --noEmit # types
210
+ npx microteia-plugin check <folder>/plugin.ts
211
+ npx microteia-plugin build <folder>/plugin.ts
212
+
213
+ \`check\` is not an approximation of the platform's validation — it *is* it, the same function and the
214
+ same messages. If \`check\` passes, the package installs.
215
+
216
+ **A package that carries code installs inert.** An administrator opens the source, reads it, and trusts
217
+ it; the trust is bound to that exact code by hash. Changing one character requires trusting it again.
218
+
219
+ ### Examples included with this version
220
+
221
+ ${examples.length === 0 ? '_None in this package._' : examples.map((id) => `- \`extensions/examples/${id}/\``).join('\n')}
222
+
223
+ Each is the real source of an extension that ships with Microteia. Build any of them and you get the
224
+ same \`.json\` the platform installs:
225
+
226
+ npx microteia-plugin build examples/pessoa/plugin.ts
227
+
228
+ ## 6. An AI assistant in this directory
229
+
230
+ \`extensions/.mcp.json\` registers an MCP server that answers from **this** installation: the extension
231
+ points it has, what a page may import, the authoring guide, and whether a package would be accepted.
232
+ \`extensions/AGENTS.md\` (and \`CLAUDE.md\`, the same content) holds the rules.
233
+
234
+ The validation tool is the part that matters — it closes the loop between what an assistant proposes and
235
+ what the platform would do with it, before anything is installed.
236
+
237
+ ## 7. Manual prerequisites
238
+
239
+ Things no command can do for you, in the Firebase or Google Cloud console:
240
+
241
+ ${manifest.manualPrerequisites.map((prerequisite) => `- **${prerequisite.title}**${prerequisite.optional ? ' _(optional)_' : ''}\n ${prerequisite.detail}`).join('\n')}
242
+ `;
243
+ };
@@ -0,0 +1,2 @@
1
+ import type { ParsedArgs } from '../shared/args.js';
2
+ export declare const pack: (args: ParsedArgs) => Promise<void>;