@mesh-tech/mesh-cli 0.36.0 → 0.37.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/assets/docs-preview.css +1599 -0
- package/dist/bin/mesh.auth-preflight-JFKL4Y4X.js +48 -0
- package/dist/bin/mesh.auth-preflight-JFKL4Y4X.js.map +6 -0
- package/dist/bin/mesh.capture-history-A4IAVVIR.js +38 -0
- package/dist/bin/mesh.capture-history-A4IAVVIR.js.map +6 -0
- package/dist/bin/mesh.chunk-5A5OFSYR.js +187 -0
- package/dist/bin/mesh.chunk-5A5OFSYR.js.map +6 -0
- package/dist/bin/mesh.chunk-7DMAFUBQ.js +7715 -0
- package/dist/bin/mesh.chunk-7DMAFUBQ.js.map +6 -0
- package/dist/bin/mesh.chunk-A4DGMGHF.js +303 -0
- package/dist/bin/mesh.chunk-A4DGMGHF.js.map +6 -0
- package/dist/bin/mesh.chunk-CQ2IC4OP.js +217 -0
- package/dist/bin/mesh.chunk-CQ2IC4OP.js.map +6 -0
- package/dist/bin/mesh.chunk-F4654EPX.js +383 -0
- package/dist/bin/mesh.chunk-F4654EPX.js.map +6 -0
- package/dist/bin/mesh.chunk-IQOBTL42.js +60 -0
- package/dist/bin/mesh.chunk-IQOBTL42.js.map +6 -0
- package/dist/bin/mesh.chunk-J6DVWKRW.js +647 -0
- package/dist/bin/mesh.chunk-J6DVWKRW.js.map +6 -0
- package/dist/bin/mesh.chunk-JB7FWYSP.js +1751 -0
- package/dist/bin/mesh.chunk-JB7FWYSP.js.map +6 -0
- package/dist/bin/mesh.chunk-MCBMHWXP.js +837 -0
- package/dist/bin/mesh.chunk-MCBMHWXP.js.map +6 -0
- package/dist/bin/mesh.chunk-OW5EMVG5.js +507 -0
- package/dist/bin/mesh.chunk-OW5EMVG5.js.map +6 -0
- package/dist/bin/mesh.chunk-R5VVTXG4.js +10092 -0
- package/dist/bin/mesh.chunk-R5VVTXG4.js.map +6 -0
- package/dist/bin/mesh.chunk-VKV6Z3UI.js +1146 -0
- package/dist/bin/mesh.chunk-VKV6Z3UI.js.map +6 -0
- package/dist/bin/mesh.chunk-WFFDF346.js +59 -0
- package/dist/bin/mesh.chunk-WFFDF346.js.map +6 -0
- package/dist/bin/mesh.chunk-WOJOTUFZ.js +835 -0
- package/dist/bin/mesh.chunk-WOJOTUFZ.js.map +6 -0
- package/dist/bin/mesh.cli-reference-H3TOPIET.js +158 -0
- package/dist/bin/mesh.cli-reference-H3TOPIET.js.map +6 -0
- package/dist/bin/mesh.convert-KK6ZP256.js +274 -0
- package/dist/bin/mesh.convert-KK6ZP256.js.map +6 -0
- package/dist/bin/mesh.create-app-A5F45PWZ.js +39 -0
- package/dist/bin/mesh.create-app-A5F45PWZ.js.map +6 -0
- package/dist/bin/mesh.dev-token-server-GYDYPXYH.js +61 -0
- package/dist/bin/mesh.dev-token-server-GYDYPXYH.js.map +6 -0
- package/dist/bin/mesh.js +20 -26418
- package/dist/bin/mesh.js.map +3 -3
- package/dist/bin/mesh.login-JNHPVMCT.js +91 -0
- package/dist/bin/mesh.login-JNHPVMCT.js.map +6 -0
- package/dist/bin/mesh.platform-setup-EB64EFRN.js +37 -0
- package/dist/bin/mesh.platform-setup-EB64EFRN.js.map +6 -0
- package/dist/bin/mesh.preview-3IP34TDO.js +2410 -0
- package/dist/bin/mesh.preview-3IP34TDO.js.map +6 -0
- package/dist/bin/mesh.program-DWOKHNMQ.js +23 -0
- package/dist/bin/mesh.program-DWOKHNMQ.js.map +6 -0
- package/dist/bin/mesh.registry-OXF57OQW.js +47 -0
- package/dist/bin/mesh.registry-OXF57OQW.js.map +6 -0
- package/dist/bin/mesh.registry-identity-2HSGQGJC.js +42 -0
- package/dist/bin/mesh.registry-identity-2HSGQGJC.js.map +6 -0
- package/dist/bin/mesh.skills-MNDSMBIE.js +23 -0
- package/dist/bin/mesh.skills-MNDSMBIE.js.map +6 -0
- package/dist/bin/mesh.src-5D5DFSLX.js +1302 -0
- package/dist/bin/mesh.src-5D5DFSLX.js.map +6 -0
- package/dist/bin/mesh.src-G7TJBLNJ.js +40 -0
- package/dist/bin/mesh.src-G7TJBLNJ.js.map +6 -0
- package/dist/bin/mesh.stack-EFTFAOCV.js +64 -0
- package/dist/bin/mesh.stack-EFTFAOCV.js.map +6 -0
- package/dist/bin/mesh.start-ARIIY6CV.js +454 -0
- package/dist/bin/mesh.start-ARIIY6CV.js.map +6 -0
- package/dist/bin/mesh.wizard-ROAQAGSF.js +500 -0
- package/dist/bin/mesh.wizard-ROAQAGSF.js.map +6 -0
- package/dist/build-info.json +2 -2
- package/dist/src/commands/app-check.d.ts +2 -1
- package/dist/src/commands/app-check.js +32 -0
- package/dist/src/commands/dev.d.ts +6 -0
- package/dist/src/commands/dev.js +152 -3
- package/dist/src/commands/docs.js +33 -0
- package/dist/src/commands/local/act-as-local.d.ts +5 -0
- package/dist/src/commands/local/act-as-local.js +41 -0
- package/dist/src/commands/local/auth-provision.d.ts +1 -0
- package/dist/src/commands/local/auth-provision.js +1 -0
- package/dist/src/commands/local/index.js +4 -0
- package/dist/src/commands/local/local-api-key.d.ts +44 -0
- package/dist/src/commands/local/local-api-key.js +115 -0
- package/dist/src/commands/local/local-spicedb.d.ts +95 -0
- package/dist/src/commands/local/local-spicedb.js +304 -0
- package/dist/src/commands/local/publish-docs.d.ts +81 -0
- package/dist/src/commands/local/publish-docs.js +328 -0
- package/dist/src/commands/local/seed-zitadel.js +2 -0
- package/dist/src/commands/temporal.js +191 -61
- package/dist/src/commands/temporal.js.map +3 -3
- package/dist/src/docs/convert.d.ts +35 -0
- package/dist/src/docs/convert.js +276 -0
- package/dist/src/docs/preview-source.d.ts +13 -0
- package/dist/src/docs/preview-source.js +58 -0
- package/dist/src/docs/preview.d.ts +32 -0
- package/dist/src/docs/preview.js +279 -0
- package/fragments/agents/AGENTS.md.hbs +27 -27
- package/fragments/base/README.md.hbs +5 -2
- package/fragments/base/index.ts.hbs +17 -30
- package/fragments/base/package.json.hbs +4 -1
- package/fragments/service/api/openapi.json.hbs +1 -1
- package/fragments/service/docs/docs.yaml.hbs +10 -0
- package/fragments/service/docs/pages/getting-started.md.hbs +6 -9
- package/package.json +19 -3
- package/skills/mesh/SKILL.md +2 -2
- package/stack/docker-compose.hub.yml +6 -0
package/dist/src/commands/dev.js
CHANGED
|
@@ -19,7 +19,11 @@ import { fingerprintWorkflowSource } from '../utils/workflow-fingerprint.js';
|
|
|
19
19
|
import { buildLaunchCommand, envFileName, waitForPort, writeEnvFile } from './dev-launch.js';
|
|
20
20
|
import { buildLocalDevOutput, detectLocalTenant, ensureLocalPlatformRunning, hasStackBacking, localAppNamespace } from './local/dev-local.js';
|
|
21
21
|
import { ensureAppTenantAuth, ensureSignInApp, registerLocalApp } from './local/auth-provision.js';
|
|
22
|
-
import { localAwsEnv, ensureTemporalNamespace } from './local/seed.js';
|
|
22
|
+
import { localAwsEnv, ensureTemporalNamespace, LOCAL_AWS_CONFIG, LOCAL_ENV } from './local/seed.js';
|
|
23
|
+
import { publishLocalDocs, readLocalPublishDeclaration, unpublishLocalDocs } from './local/publish-docs.js';
|
|
24
|
+
import { actAsEnv, publishLocalHubActAsKey } from './local/act-as-local.js';
|
|
25
|
+
import { ensureLocalApiKey, ensureLocalStaffKey, readLocalKeyDeclaration } from './local/local-api-key.js';
|
|
26
|
+
import { api as zitadelApi, readHubAuth, readSeederPat } from './local/seed-zitadel.js';
|
|
23
27
|
import { composeExternalUp, composeExternalsDown, externalMode, localProbesRemove, parseExternalsSelection, readLocalMocks, seedLocalMock, } from './local/mocks.js';
|
|
24
28
|
import { logShipperPath } from './local/dev-local.js';
|
|
25
29
|
import { writeAppServiceProbes } from './local/stack.js';
|
|
@@ -565,9 +569,49 @@ export function buildChildAwsEnv(awsEnv, method, profile, opts) {
|
|
|
565
569
|
}
|
|
566
570
|
return result;
|
|
567
571
|
}
|
|
568
|
-
function
|
|
572
|
+
export function readDotEnvFile(file) {
|
|
573
|
+
let text;
|
|
574
|
+
try {
|
|
575
|
+
text = fs.readFileSync(file, 'utf-8');
|
|
576
|
+
}
|
|
577
|
+
catch {
|
|
578
|
+
return {};
|
|
579
|
+
}
|
|
580
|
+
const out = {};
|
|
581
|
+
for (const raw of text.split(/\r?\n/)) {
|
|
582
|
+
const line = raw.trim();
|
|
583
|
+
if (!line || line.startsWith('#'))
|
|
584
|
+
continue;
|
|
585
|
+
const eq = line.indexOf('=');
|
|
586
|
+
if (eq <= 0)
|
|
587
|
+
continue;
|
|
588
|
+
const key = line.slice(0, eq).replace(/^export\s+/, '').trim();
|
|
589
|
+
let value = line.slice(eq + 1).trim();
|
|
590
|
+
if (value[0] === '"' || value[0] === "'") {
|
|
591
|
+
const close = value.indexOf(value[0], 1);
|
|
592
|
+
value = close > 0 ? value.slice(1, close) : value.slice(1);
|
|
593
|
+
}
|
|
594
|
+
else {
|
|
595
|
+
const hash = value.search(/\s#/);
|
|
596
|
+
if (hash >= 0)
|
|
597
|
+
value = value.slice(0, hash).trimEnd();
|
|
598
|
+
}
|
|
599
|
+
out[key] = value;
|
|
600
|
+
}
|
|
601
|
+
return out;
|
|
602
|
+
}
|
|
603
|
+
async function unpublishSessionDocs(localDocs) {
|
|
604
|
+
if (!localDocs)
|
|
605
|
+
return;
|
|
606
|
+
const removed = await unpublishLocalDocs(localDocs.tenant, localDocs.app, LOCAL_AWS_CONFIG);
|
|
607
|
+
if (removed.length > 0)
|
|
608
|
+
logInfo(`Took ${localDocs.app}'s docs off the local Hub (${removed.join(', ')}).`);
|
|
609
|
+
}
|
|
610
|
+
export function rebaseServiceSrc(src, monorepoRoot) {
|
|
569
611
|
if (!monorepoRoot)
|
|
570
612
|
return src;
|
|
613
|
+
if (src === '.' || src === './')
|
|
614
|
+
return src;
|
|
571
615
|
const rel = monorepoRelativeSrc(src);
|
|
572
616
|
if (rel === null)
|
|
573
617
|
return src;
|
|
@@ -1623,6 +1667,7 @@ export function registerDevCommand(program) {
|
|
|
1623
1667
|
dockerDevDown(sessionName);
|
|
1624
1668
|
composeExternalsDown(loadSessionState(sessionName)?.composeExternals);
|
|
1625
1669
|
localProbesRemove(loadSessionState(sessionName)?.externalProbeFiles);
|
|
1670
|
+
await unpublishSessionDocs(loadSessionState(sessionName)?.localDocs);
|
|
1626
1671
|
removeSessionState(sessionName);
|
|
1627
1672
|
logSuccess(`Killed docker dev session: ${sessionName}`);
|
|
1628
1673
|
}
|
|
@@ -1634,6 +1679,7 @@ export function registerDevCommand(program) {
|
|
|
1634
1679
|
if (options.kill) {
|
|
1635
1680
|
composeExternalsDown(loadSessionState(sessionName)?.composeExternals);
|
|
1636
1681
|
localProbesRemove(loadSessionState(sessionName)?.externalProbeFiles);
|
|
1682
|
+
await unpublishSessionDocs(loadSessionState(sessionName)?.localDocs);
|
|
1637
1683
|
try {
|
|
1638
1684
|
const devOutput = loadSessionState(sessionName)?.devOutput;
|
|
1639
1685
|
if (devOutput) {
|
|
@@ -1672,6 +1718,7 @@ export function registerDevCommand(program) {
|
|
|
1672
1718
|
if (options.kill) {
|
|
1673
1719
|
composeExternalsDown(loadSessionState(sessionName)?.composeExternals);
|
|
1674
1720
|
localProbesRemove(loadSessionState(sessionName)?.externalProbeFiles);
|
|
1721
|
+
await unpublishSessionDocs(loadSessionState(sessionName)?.localDocs);
|
|
1675
1722
|
if (loadSessionState(sessionName)?.runner === 'docker') {
|
|
1676
1723
|
dockerDevDown(sessionName);
|
|
1677
1724
|
removeSessionState(sessionName);
|
|
@@ -1774,7 +1821,9 @@ export function registerDevCommand(program) {
|
|
|
1774
1821
|
return;
|
|
1775
1822
|
}
|
|
1776
1823
|
let signInServices = [];
|
|
1824
|
+
let provisioned;
|
|
1777
1825
|
let appVersion;
|
|
1826
|
+
let appDisplayName;
|
|
1778
1827
|
try {
|
|
1779
1828
|
const tenant = localTenant;
|
|
1780
1829
|
const app = rawDevOutput.app ?? projectName;
|
|
@@ -1793,10 +1842,13 @@ export function registerDevCommand(program) {
|
|
|
1793
1842
|
}
|
|
1794
1843
|
if (typeof appPkg?.version === 'string')
|
|
1795
1844
|
appVersion = appPkg.version;
|
|
1845
|
+
if (typeof appPkg?.mesh?.displayName === 'string' && appPkg.mesh.displayName) {
|
|
1846
|
+
appDisplayName = appPkg.mesh.displayName;
|
|
1847
|
+
}
|
|
1796
1848
|
}
|
|
1797
1849
|
catch {
|
|
1798
1850
|
}
|
|
1799
|
-
await ensureAppTenantAuth({ tenant, app, services: authServices, roles: authRoles });
|
|
1851
|
+
provisioned = await ensureAppTenantAuth({ tenant, app, services: authServices, roles: authRoles });
|
|
1800
1852
|
await ensureTemporalNamespace(localAppNamespace(tenant, app));
|
|
1801
1853
|
}
|
|
1802
1854
|
catch (err) {
|
|
@@ -1828,6 +1880,7 @@ export function registerDevCommand(program) {
|
|
|
1828
1880
|
tenant: localTenant,
|
|
1829
1881
|
app: devOutput.app ?? projectName,
|
|
1830
1882
|
version: appVersion,
|
|
1883
|
+
...(appDisplayName ? { displayName: appDisplayName } : {}),
|
|
1831
1884
|
services: Object.keys(devOutput.services),
|
|
1832
1885
|
ports: Object.fromEntries(Object.entries(devOutput.services).map(([name, svc]) => [name, svc.port])),
|
|
1833
1886
|
kinds: Object.fromEntries(Object.entries(devOutput.services).flatMap(([name, svc]) => svc.kind ? [[name, svc.kind]] : [])),
|
|
@@ -1839,6 +1892,100 @@ export function registerDevCommand(program) {
|
|
|
1839
1892
|
catch (err) {
|
|
1840
1893
|
logWarn(`Local registry registration skipped: ${err instanceof Error ? err.message : err}`);
|
|
1841
1894
|
}
|
|
1895
|
+
let localDocs;
|
|
1896
|
+
try {
|
|
1897
|
+
const appPkg = JSON.parse(fs.readFileSync(path.join(appRoot, 'package.json'), 'utf-8'));
|
|
1898
|
+
const declaration = readLocalPublishDeclaration(appPkg, appRoot);
|
|
1899
|
+
if (declaration.docs || declaration.authzMetadata || declaration.problems.length > 0) {
|
|
1900
|
+
const app = devOutput.app ?? projectName;
|
|
1901
|
+
const serviceNames = Object.keys(devOutput.services).filter((n) => !n.startsWith('mock-'));
|
|
1902
|
+
const httpService = declaration.docs?.service ?? serviceNames[0];
|
|
1903
|
+
const service = httpService ? devOutput.services[httpService] : undefined;
|
|
1904
|
+
if (!httpService || !service?.port) {
|
|
1905
|
+
logWarn(`mesh.docs names service '${httpService ?? ''}', which this app does not run — docs not published.`);
|
|
1906
|
+
}
|
|
1907
|
+
else {
|
|
1908
|
+
const serviceDir = path.resolve(appRoot, service.src);
|
|
1909
|
+
const env = service.env ?? (service.env = {});
|
|
1910
|
+
const serviceEnv = {
|
|
1911
|
+
...readDotEnvFile(path.join(serviceDir, '.env')),
|
|
1912
|
+
...Object.fromEntries(Object.entries(process.env).filter((e) => typeof e[1] === 'string')),
|
|
1913
|
+
...Object.fromEntries(Object.entries(env).map(([k, v]) => [k, v.value])),
|
|
1914
|
+
};
|
|
1915
|
+
const published = await publishLocalDocs({
|
|
1916
|
+
appRoot,
|
|
1917
|
+
tenant: localTenant,
|
|
1918
|
+
app,
|
|
1919
|
+
httpPort: service.port,
|
|
1920
|
+
serviceEnv,
|
|
1921
|
+
...(provisioned
|
|
1922
|
+
? { zitadel: { orgId: provisioned.orgId, projectId: provisioned.projectId, issuer: 'http://localhost:8080' } }
|
|
1923
|
+
: {}),
|
|
1924
|
+
awsConfig: LOCAL_AWS_CONFIG,
|
|
1925
|
+
declaration,
|
|
1926
|
+
});
|
|
1927
|
+
for (const [key, value] of Object.entries(published.pins))
|
|
1928
|
+
env[key] = { value };
|
|
1929
|
+
for (const [key, value] of Object.entries(published.authzEnv))
|
|
1930
|
+
env[key] = { value };
|
|
1931
|
+
if (published.sandbox)
|
|
1932
|
+
env.INTEGRATION_SANDBOX = { value: published.sandbox };
|
|
1933
|
+
if (published.actAs) {
|
|
1934
|
+
const publication = await publishLocalHubActAsKey(LOCAL_AWS_CONFIG);
|
|
1935
|
+
if (!publication) {
|
|
1936
|
+
logWarn('The local Hub has no machine key yet — try-it cannot reach this app. Run: mesh start');
|
|
1937
|
+
}
|
|
1938
|
+
else {
|
|
1939
|
+
for (const [key, value] of Object.entries(actAsEnv(publication, localTenant, LOCAL_ENV, app))) {
|
|
1940
|
+
env[key] = { value };
|
|
1941
|
+
}
|
|
1942
|
+
const relays = declaration.docs?.integrationTryIt ?? [];
|
|
1943
|
+
if (relays.length > 0)
|
|
1944
|
+
env.INTEGRATION_TRY_IT_INTEGRATIONS = { value: relays.join(",") };
|
|
1945
|
+
}
|
|
1946
|
+
}
|
|
1947
|
+
if (published.docsPublished) {
|
|
1948
|
+
localDocs = { tenant: localTenant, app };
|
|
1949
|
+
logInfo(`Published ${app}'s docs to the local Hub (sandbox: ${published.sandbox}` +
|
|
1950
|
+
`${published.actAs ? ', try-it on' : ', try-it off'}` +
|
|
1951
|
+
`${Object.keys(published.pins).length ? `; pinned ${Object.entries(published.pins).map(([k, v]) => `${k}=${v}`).join(' ')}` : ''}).`);
|
|
1952
|
+
}
|
|
1953
|
+
if (published.authzPublished) {
|
|
1954
|
+
logInfo(`Published ${app}'s API-key metadata to the local Hub` +
|
|
1955
|
+
`${Object.keys(published.authzEnv).length ? ' — its schema is on the local SpiceDB, so key bundles take effect in the app' : ''}.`);
|
|
1956
|
+
const keyDecl = readLocalKeyDeclaration(appPkg);
|
|
1957
|
+
const hubProjectId = readHubAuth()?.projectId;
|
|
1958
|
+
if (keyDecl && hubProjectId) {
|
|
1959
|
+
try {
|
|
1960
|
+
const staffKey = await ensureLocalStaffKey({
|
|
1961
|
+
pat: readSeederPat(),
|
|
1962
|
+
api: zitadelApi,
|
|
1963
|
+
hubProjectId,
|
|
1964
|
+
awsConfig: LOCAL_AWS_CONFIG,
|
|
1965
|
+
});
|
|
1966
|
+
const key = await ensureLocalApiKey({ tenant: localTenant, app, declaration: keyDecl, staffKey });
|
|
1967
|
+
logInfo(key.kind === 'minted'
|
|
1968
|
+
? `Minted local API key '${key.name}' for ${app} (${keyDecl.bundles.join(', ') || 'no bundles'}) — try-it runs as it.`
|
|
1969
|
+
: `Local API key '${key.name}' for ${app} is active — try-it runs as it.`);
|
|
1970
|
+
}
|
|
1971
|
+
catch (err) {
|
|
1972
|
+
logWarn(`No local API key for ${app}: ${err instanceof Error ? err.message : err} — mint one on the app's Access tab.`);
|
|
1973
|
+
}
|
|
1974
|
+
}
|
|
1975
|
+
else if (keyDecl) {
|
|
1976
|
+
logWarn(`No local API key for ${app}: the local Hub is not seeded yet (run: mesh start).`);
|
|
1977
|
+
}
|
|
1978
|
+
}
|
|
1979
|
+
for (const note of published.notes)
|
|
1980
|
+
logWarn(`docs: ${note}`);
|
|
1981
|
+
for (const problem of published.problems)
|
|
1982
|
+
logWarn(`docs source: ${problem}`);
|
|
1983
|
+
}
|
|
1984
|
+
}
|
|
1985
|
+
}
|
|
1986
|
+
catch (err) {
|
|
1987
|
+
logWarn(`Local docs publishing stopped: ${err instanceof Error ? err.message : err}`);
|
|
1988
|
+
}
|
|
1842
1989
|
const composeExternals = [];
|
|
1843
1990
|
const externalProbeFiles = [];
|
|
1844
1991
|
for (const [name, decl] of Object.entries(selectedMocks)) {
|
|
@@ -1913,6 +2060,7 @@ export function registerDevCommand(program) {
|
|
|
1913
2060
|
runner: 'docker',
|
|
1914
2061
|
composeExternals,
|
|
1915
2062
|
externalProbeFiles,
|
|
2063
|
+
...(localDocs ? { localDocs } : {}),
|
|
1916
2064
|
});
|
|
1917
2065
|
console.log('');
|
|
1918
2066
|
logSuccess(`Dev session started (docker): ${sessionName}`);
|
|
@@ -1936,6 +2084,7 @@ export function registerDevCommand(program) {
|
|
|
1936
2084
|
runner: 'tmux',
|
|
1937
2085
|
composeExternals,
|
|
1938
2086
|
externalProbeFiles,
|
|
2087
|
+
...(localDocs ? { localDocs } : {}),
|
|
1939
2088
|
});
|
|
1940
2089
|
return;
|
|
1941
2090
|
}
|
|
@@ -122,6 +122,7 @@ async function buildDocs(configPathArg) {
|
|
|
122
122
|
}
|
|
123
123
|
logSuccess(`Docs build complete (${generatedSpecs.size} OpenAPI file${generatedSpecs.size === 1 ? "" : "s"})`);
|
|
124
124
|
}
|
|
125
|
+
const DOCS_PREVIEW_PORT = "4410";
|
|
125
126
|
const CLI_REFERENCE_PATH = "docs/portal/generated/cli-reference.md";
|
|
126
127
|
async function renderCliReference() {
|
|
127
128
|
const [{ createProgram }, { extractCliReference, renderCliReferenceMarkdown }] = await Promise.all([
|
|
@@ -240,6 +241,38 @@ export function registerDocsCommand(program) {
|
|
|
240
241
|
const { runDocsServeStatic } = await import("../docs/start.js");
|
|
241
242
|
await runDocsServeStatic(opts);
|
|
242
243
|
})());
|
|
244
|
+
docs
|
|
245
|
+
.command("preview")
|
|
246
|
+
.description("Render one app's docs source locally — its docs.yaml, Markdown guides and OpenAPI reference, as the Hub's Docs tab shows them — with no Hub and no platform. Every problem the deploy would refuse is printed and shown on the page; try-it runs in the Hub only")
|
|
247
|
+
.argument("<dir>", "the directory that holds docs.yaml, or the docs.yaml file itself")
|
|
248
|
+
.option("-p, --port <port>", "port to serve on, on localhost (0 picks a free one; a port in use fails)", DOCS_PREVIEW_PORT)
|
|
249
|
+
.option("-o, --out <file>", "write the assembled docs-source bundle (JSON) to this file and exit — the file HUB_LOCAL_DOCS_SOURCES points a local Hub at")
|
|
250
|
+
.option("-s, --spec <file>", "the OpenAPI spec to document, overriding docs.yaml's spec — pass the one the deploy reads (the ApiSurface's docs.spec, or its doc package's openapi.json); default: docs.yaml's spec, else openapi.json beside it")
|
|
251
|
+
.option("--check", "print the problems and exit 1 when there are any, without serving (CI / pre-deploy)", false)
|
|
252
|
+
.action((dir, opts) => guarded(async () => {
|
|
253
|
+
const { runDocsPreview } = await import("../docs/preview.js");
|
|
254
|
+
const ok = await runDocsPreview({ target: dir, port: opts.port, out: opts.out, spec: opts.spec, check: opts.check });
|
|
255
|
+
if (!ok)
|
|
256
|
+
process.exitCode = 1;
|
|
257
|
+
})());
|
|
258
|
+
docs
|
|
259
|
+
.command("convert")
|
|
260
|
+
.description("Write a starter docs.yaml — a native docs source the Hub renders itself — from the inputs of an ApiSurface's site-shaped docs block (spec, pages, landingPage), then assemble it as the deploy does and print every problem left and the ApiSurface edit to make. Exits 1 while problems remain; replaces nothing without --force")
|
|
261
|
+
.requiredOption("-s, --spec <file>", "the OpenAPI spec the surface documents (the block's docs.spec)")
|
|
262
|
+
.option("--pages <dir>", "the block's docs.pages directory of Markdown guides")
|
|
263
|
+
.option("--landing <page>", "the block's docs.landingPage — a file, or a page id under --pages (default: the index page under --pages, when there is one)")
|
|
264
|
+
.option("--title <title>", "the source's title (default: the spec's info.title)")
|
|
265
|
+
.option("-o, --out <dir>", "where docs.yaml is written (default: the pages directory's parent, else the spec's directory)")
|
|
266
|
+
.option("--fix-pages", "rewrite pages for the native rules: a leading # heading becomes the front-matter title, and a landing file outside --pages is copied to <pages>/index.md; .mdx pages are reported, never converted", false)
|
|
267
|
+
.option("--force", "replace an existing docs.yaml, and a page the landing copy would land on", false)
|
|
268
|
+
.option("--root <dir>", "the Pulumi program's directory, which the printed ApiSurface edit's paths are relative to (default: the working directory)")
|
|
269
|
+
.option("--prefix <prefix>", "the block's pages prefix ({ dir, prefix }): the old site served pages under /<prefix>/; the conversion lists the page ids that lose it")
|
|
270
|
+
.action((opts) => guarded(async () => {
|
|
271
|
+
const { runDocsConvert } = await import("../docs/convert.js");
|
|
272
|
+
const ok = await runDocsConvert(opts);
|
|
273
|
+
if (!ok)
|
|
274
|
+
process.exitCode = 1;
|
|
275
|
+
})());
|
|
243
276
|
docs
|
|
244
277
|
.command("list")
|
|
245
278
|
.description("List the published docs versions (each is an @mesh-tech/* baseline)")
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type HubActAsExports } from "@mesh-tech/api-registry";
|
|
2
|
+
export declare const LOCAL_OPS_HUB_SECRET_ID = "mesh/local/dev/zitadel/ops-hub";
|
|
3
|
+
export declare function hubActAsPublication(secretString: string): HubActAsExports;
|
|
4
|
+
export declare function publishLocalHubActAsKey(awsConfig: object): Promise<HubActAsExports | undefined>;
|
|
5
|
+
export declare function actAsEnv(publication: HubActAsExports, tenant: string, env: string, surface: string): Record<string, string>;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { createPublicKey } from "node:crypto";
|
|
2
|
+
import { actAsAudience, hubActAsPath, parseHubActAsExports } from "@mesh-tech/api-registry";
|
|
3
|
+
import { LOCAL_ENV, LOCAL_TENANT } from "./seed.js";
|
|
4
|
+
export const LOCAL_OPS_HUB_SECRET_ID = "mesh/local/dev/zitadel/ops-hub";
|
|
5
|
+
export function hubActAsPublication(secretString) {
|
|
6
|
+
const parsed = JSON.parse(secretString);
|
|
7
|
+
if (typeof parsed.keyId !== "string" || typeof parsed.key !== "string" || typeof parsed.userId !== "string") {
|
|
8
|
+
throw new Error("the Hub's machine key has no keyId/key/userId");
|
|
9
|
+
}
|
|
10
|
+
const jwk = createPublicKey(parsed.key).export({ format: "jwk" });
|
|
11
|
+
if (jwk.kty !== "RSA" || !jwk.n || !jwk.e)
|
|
12
|
+
throw new Error("the Hub's machine key is not an RSA key");
|
|
13
|
+
return parseHubActAsExports({
|
|
14
|
+
issuer: parsed.userId,
|
|
15
|
+
keys: [{ kid: parsed.keyId, kty: "RSA", n: jwk.n, e: jwk.e, alg: "RS256", use: "sig" }],
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
export async function publishLocalHubActAsKey(awsConfig) {
|
|
19
|
+
const { SecretsManagerClient, GetSecretValueCommand } = await import("@aws-sdk/client-secrets-manager");
|
|
20
|
+
const { SSMClient, PutParameterCommand } = await import("@aws-sdk/client-ssm");
|
|
21
|
+
const secret = await new SecretsManagerClient(awsConfig)
|
|
22
|
+
.send(new GetSecretValueCommand({ SecretId: LOCAL_OPS_HUB_SECRET_ID }))
|
|
23
|
+
.catch(() => null);
|
|
24
|
+
if (!secret?.SecretString)
|
|
25
|
+
return undefined;
|
|
26
|
+
const publication = hubActAsPublication(secret.SecretString);
|
|
27
|
+
await new SSMClient(awsConfig).send(new PutParameterCommand({
|
|
28
|
+
Name: hubActAsPath(LOCAL_TENANT, LOCAL_ENV),
|
|
29
|
+
Type: "String",
|
|
30
|
+
Overwrite: true,
|
|
31
|
+
Value: JSON.stringify(publication),
|
|
32
|
+
Description: "Hub act-as key — the public half of the local Hub's machine key",
|
|
33
|
+
}));
|
|
34
|
+
return publication;
|
|
35
|
+
}
|
|
36
|
+
export function actAsEnv(publication, tenant, env, surface) {
|
|
37
|
+
return {
|
|
38
|
+
INTEGRATION_ACT_AS_KEYS: JSON.stringify(publication),
|
|
39
|
+
INTEGRATION_ACT_AS_AUDIENCE: actAsAudience(tenant, env, surface),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
@@ -14,6 +14,7 @@ export declare function registerLocalApp(args: AppTenantAuthArgs & {
|
|
|
14
14
|
ports?: Record<string, number>;
|
|
15
15
|
links?: string[];
|
|
16
16
|
version?: string;
|
|
17
|
+
displayName?: string;
|
|
17
18
|
kinds?: Record<string, string>;
|
|
18
19
|
}): Promise<string>;
|
|
19
20
|
export declare function reconcileRegistryFromZitadel(): Promise<{
|
|
@@ -138,6 +138,7 @@ export async function registerLocalApp(args) {
|
|
|
138
138
|
services: args.services,
|
|
139
139
|
ports: args.ports ?? {},
|
|
140
140
|
...(args.version ? { version: args.version } : {}),
|
|
141
|
+
...(args.displayName ? { displayName: args.displayName } : {}),
|
|
141
142
|
deployedAt: new Date().toISOString(),
|
|
142
143
|
}, "Local run metadata (mesh dev --local)");
|
|
143
144
|
logSuccess(`Registered app in the local registry → ${base}`);
|
|
@@ -11,6 +11,7 @@ import { LOCAL_AWS_CONFIG, localAwsEnv, seedLocalPlatform, verifyFabric } from "
|
|
|
11
11
|
import { LOGIN_CONTEXT, readHubAuth, seedMockIdps, seedZitadel, TEST_USERS } from "./seed-zitadel.js";
|
|
12
12
|
import { idpEndpoints, mockIdpComposeEnv, MOCK_OIDC_PORT, MOCK_SAML_PORT } from "./mock-idps.js";
|
|
13
13
|
import { publishHubAuthzCatalog } from "./seed-hub-catalog.js";
|
|
14
|
+
import { removeAllAliasContainers } from "./publish-docs.js";
|
|
14
15
|
import { describePortConflicts, findPortConflicts, hostPortsOf } from "./helpers.js";
|
|
15
16
|
const WAIT_TIMEOUT_MS = 180_000;
|
|
16
17
|
const WAIT_POLL_MS = 3_000;
|
|
@@ -313,6 +314,9 @@ export function registerLocalCommands(program) {
|
|
|
313
314
|
if (foreign && !opts.force) {
|
|
314
315
|
throw new MeshCliError(`The running local platform was started from a different checkout (${foreign}) — another project may be using it.`, { remediation: { command: "mesh stop --force # stop it anyway" } });
|
|
315
316
|
}
|
|
317
|
+
const aliases = removeAllAliasContainers();
|
|
318
|
+
if (aliases.length > 0)
|
|
319
|
+
logInfo(`Removed ${aliases.length} local docs alias container(s).`);
|
|
316
320
|
const args = ["down"];
|
|
317
321
|
if (opts.destroy)
|
|
318
322
|
args.push("-v");
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export declare const LOCAL_CLI_SECRET_ID = "mesh/local/dev/zitadel/local-cli";
|
|
2
|
+
export interface LocalKeyDeclaration {
|
|
3
|
+
name: string;
|
|
4
|
+
bundles: string[];
|
|
5
|
+
rateLimit: number;
|
|
6
|
+
}
|
|
7
|
+
export declare function readLocalKeyDeclaration(pkg: unknown): LocalKeyDeclaration | undefined;
|
|
8
|
+
export declare function jwtBearerAssertion(key: {
|
|
9
|
+
keyId: string;
|
|
10
|
+
key: string;
|
|
11
|
+
userId: string;
|
|
12
|
+
}, audience: string, nowSeconds?: number): string;
|
|
13
|
+
type ZitadelApi = (pat: string, method: string, apiPath: string, body?: unknown) => Promise<any>;
|
|
14
|
+
export declare function ensureLocalStaffKey(input: {
|
|
15
|
+
pat: string;
|
|
16
|
+
api: ZitadelApi;
|
|
17
|
+
hubProjectId: string;
|
|
18
|
+
awsConfig: object;
|
|
19
|
+
}): Promise<{
|
|
20
|
+
keyId: string;
|
|
21
|
+
key: string;
|
|
22
|
+
userId: string;
|
|
23
|
+
}>;
|
|
24
|
+
export type LocalKeyOutcome = {
|
|
25
|
+
kind: "kept";
|
|
26
|
+
name: string;
|
|
27
|
+
id: string;
|
|
28
|
+
} | {
|
|
29
|
+
kind: "minted";
|
|
30
|
+
name: string;
|
|
31
|
+
id: string;
|
|
32
|
+
clientId: string;
|
|
33
|
+
};
|
|
34
|
+
export declare function ensureLocalApiKey(input: {
|
|
35
|
+
tenant: string;
|
|
36
|
+
app: string;
|
|
37
|
+
declaration: LocalKeyDeclaration;
|
|
38
|
+
staffKey: {
|
|
39
|
+
keyId: string;
|
|
40
|
+
key: string;
|
|
41
|
+
userId: string;
|
|
42
|
+
};
|
|
43
|
+
}): Promise<LocalKeyOutcome>;
|
|
44
|
+
export {};
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { createSign, randomUUID } from "node:crypto";
|
|
2
|
+
import { LOCAL_ENV } from "./seed.js";
|
|
3
|
+
export const LOCAL_CLI_SECRET_ID = "mesh/local/dev/zitadel/local-cli";
|
|
4
|
+
const ISSUER = "http://localhost:8080";
|
|
5
|
+
const HUB_API = "http://localhost:4568";
|
|
6
|
+
export function readLocalKeyDeclaration(pkg) {
|
|
7
|
+
const authz = pkg?.mesh?.authz;
|
|
8
|
+
if (typeof authz?.metadata !== "string")
|
|
9
|
+
return undefined;
|
|
10
|
+
const key = (authz.localKey ?? {});
|
|
11
|
+
return {
|
|
12
|
+
name: typeof key.name === "string" && key.name ? key.name : "local-try-it",
|
|
13
|
+
bundles: Array.isArray(key.bundles) ? key.bundles.filter((b) => typeof b === "string") : [],
|
|
14
|
+
rateLimit: typeof key.rateLimit === "number" && key.rateLimit > 0 ? key.rateLimit : 600,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export function jwtBearerAssertion(key, audience, nowSeconds = Math.floor(Date.now() / 1000)) {
|
|
18
|
+
const b64 = (value) => Buffer.from(JSON.stringify(value)).toString("base64url");
|
|
19
|
+
const header = b64({ alg: "RS256", kid: key.keyId });
|
|
20
|
+
const payload = b64({ iss: key.userId, sub: key.userId, aud: audience, iat: nowSeconds, exp: nowSeconds + 300 });
|
|
21
|
+
const signature = createSign("RSA-SHA256").update(`${header}.${payload}`).sign(key.key).toString("base64url");
|
|
22
|
+
return `${header}.${payload}.${signature}`;
|
|
23
|
+
}
|
|
24
|
+
export async function ensureLocalStaffKey(input) {
|
|
25
|
+
const { SecretsManagerClient, GetSecretValueCommand, CreateSecretCommand, PutSecretValueCommand } = await import("@aws-sdk/client-secrets-manager");
|
|
26
|
+
const sm = new SecretsManagerClient(input.awsConfig);
|
|
27
|
+
const ensureGrant = async (userId) => {
|
|
28
|
+
try {
|
|
29
|
+
await input.api(input.pat, "POST", `/management/v1/users/${userId}/grants`, {
|
|
30
|
+
projectId: input.hubProjectId,
|
|
31
|
+
roleKeys: ["ops"],
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
catch (err) {
|
|
35
|
+
if (err.status !== 409)
|
|
36
|
+
throw err;
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
const existing = await sm.send(new GetSecretValueCommand({ SecretId: LOCAL_CLI_SECRET_ID })).catch(() => null);
|
|
40
|
+
if (existing?.SecretString) {
|
|
41
|
+
const kept = JSON.parse(existing.SecretString);
|
|
42
|
+
await ensureGrant(kept.userId);
|
|
43
|
+
return kept;
|
|
44
|
+
}
|
|
45
|
+
const userName = "mesh-local-cli";
|
|
46
|
+
const found = await input.api(input.pat, "POST", "/management/v1/users/_search", {
|
|
47
|
+
queries: [{ userNameQuery: { userName, method: "TEXT_QUERY_METHOD_EQUALS" } }],
|
|
48
|
+
});
|
|
49
|
+
let userId = found?.result?.[0]?.id;
|
|
50
|
+
if (!userId) {
|
|
51
|
+
const created = await input.api(input.pat, "POST", "/management/v1/users/machine", {
|
|
52
|
+
userName,
|
|
53
|
+
name: "mesh CLI (local)",
|
|
54
|
+
description: "Local staff caller the mesh CLI uses against the local Hub (mesh dev --local)",
|
|
55
|
+
accessTokenType: "ACCESS_TOKEN_TYPE_JWT",
|
|
56
|
+
});
|
|
57
|
+
userId = created?.userId;
|
|
58
|
+
}
|
|
59
|
+
if (!userId)
|
|
60
|
+
throw new Error("the local Zitadel did not create the CLI's staff caller");
|
|
61
|
+
await ensureGrant(userId);
|
|
62
|
+
const created = await input.api(input.pat, "POST", `/management/v1/users/${userId}/keys`, { type: "KEY_TYPE_JSON" });
|
|
63
|
+
if (!created?.keyDetails)
|
|
64
|
+
throw new Error("the local Zitadel returned no key for the CLI's staff caller");
|
|
65
|
+
const raw = JSON.parse(Buffer.from(created.keyDetails, "base64").toString("utf8"));
|
|
66
|
+
const key = { keyId: raw.keyId, key: raw.key, userId: raw.userId };
|
|
67
|
+
await sm
|
|
68
|
+
.send(new CreateSecretCommand({ Name: LOCAL_CLI_SECRET_ID, SecretString: JSON.stringify(key) }))
|
|
69
|
+
.catch(() => sm.send(new PutSecretValueCommand({ SecretId: LOCAL_CLI_SECRET_ID, SecretString: JSON.stringify(key) })));
|
|
70
|
+
return key;
|
|
71
|
+
}
|
|
72
|
+
async function staffToken(key) {
|
|
73
|
+
const res = await fetch(`${ISSUER}/oauth/v2/token`, {
|
|
74
|
+
method: "POST",
|
|
75
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
76
|
+
body: new URLSearchParams({
|
|
77
|
+
grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer",
|
|
78
|
+
assertion: jwtBearerAssertion(key, ISSUER),
|
|
79
|
+
scope: "openid profile",
|
|
80
|
+
}),
|
|
81
|
+
});
|
|
82
|
+
const body = (await res.json().catch(() => ({})));
|
|
83
|
+
if (!res.ok || !body.access_token)
|
|
84
|
+
throw new Error(`the local Zitadel refused a token: ${body.error_description ?? res.status}`);
|
|
85
|
+
return body.access_token;
|
|
86
|
+
}
|
|
87
|
+
export async function ensureLocalApiKey(input) {
|
|
88
|
+
const token = await staffToken(input.staffKey);
|
|
89
|
+
const base = `${HUB_API}/tenants/${encodeURIComponent(input.tenant)}/environments/${LOCAL_ENV}/api-keys`;
|
|
90
|
+
const headers = { Authorization: `Bearer ${token}`, "Content-Type": "application/json" };
|
|
91
|
+
const listed = await fetch(`${base}?app=${encodeURIComponent(input.app)}`, { headers });
|
|
92
|
+
if (!listed.ok)
|
|
93
|
+
throw new Error(`the local Hub refused the key list (${listed.status}: ${await listed.text()})`);
|
|
94
|
+
const keys = (await listed.json());
|
|
95
|
+
const kept = keys.find((k) => k.name === input.declaration.name && k.status === "active");
|
|
96
|
+
if (kept)
|
|
97
|
+
return { kind: "kept", name: kept.name, id: kept.id };
|
|
98
|
+
const res = await fetch(base, {
|
|
99
|
+
method: "POST",
|
|
100
|
+
headers,
|
|
101
|
+
body: JSON.stringify({
|
|
102
|
+
app: input.app,
|
|
103
|
+
name: input.declaration.name,
|
|
104
|
+
rateLimit: input.declaration.rateLimit,
|
|
105
|
+
idempotencyKey: `mesh-local-${randomUUID()}`,
|
|
106
|
+
...(input.declaration.bundles.length
|
|
107
|
+
? { assignments: input.declaration.bundles.map((bundle) => ({ bundle, reason: "mesh dev --local try-it key" })) }
|
|
108
|
+
: {}),
|
|
109
|
+
}),
|
|
110
|
+
});
|
|
111
|
+
const body = (await res.json().catch(() => ({})));
|
|
112
|
+
if (!res.ok || !body.id)
|
|
113
|
+
throw new Error(`the local Hub did not mint the key (${res.status} ${body.code ?? ""}: ${body.error ?? ""})`);
|
|
114
|
+
return { kind: "minted", name: input.declaration.name, id: body.id, clientId: body.credentials?.clientId ?? "" };
|
|
115
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
export declare const LOCAL_SPICEDB_INSTANCE_ID = "mesh-local";
|
|
2
|
+
export declare const LOCAL_SPICEDB_KEY = "local-dev-key";
|
|
3
|
+
export declare const LOCAL_SPICEDB_KEY_SECRET = "mesh/local/dev/spicedb/preshared-key";
|
|
4
|
+
export interface LocalSpicedbRef {
|
|
5
|
+
tenant: string;
|
|
6
|
+
env: string;
|
|
7
|
+
instanceId: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function localSpicedbInstancePath(tenant: string): string;
|
|
10
|
+
export declare function localSpicedbInstanceValue(): {
|
|
11
|
+
grpcEndpoint: string;
|
|
12
|
+
httpEndpoint: string;
|
|
13
|
+
namespace: string;
|
|
14
|
+
presharedKeySecretName: string;
|
|
15
|
+
configSecretName: string;
|
|
16
|
+
owner: {
|
|
17
|
+
kind: "shared-stack";
|
|
18
|
+
name: string;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
export declare function localSpicedbRef(tenant: string): LocalSpicedbRef;
|
|
22
|
+
export declare function localAuthzServiceEnv(tenant: string, app: string): Record<string, string>;
|
|
23
|
+
export interface ZedSchema {
|
|
24
|
+
uses: string[];
|
|
25
|
+
blocks: {
|
|
26
|
+
name: string;
|
|
27
|
+
text: string;
|
|
28
|
+
}[];
|
|
29
|
+
}
|
|
30
|
+
export declare function parseZed(schema: string): ZedSchema;
|
|
31
|
+
export declare function zedBlocks(schema: string): {
|
|
32
|
+
name: string;
|
|
33
|
+
text: string;
|
|
34
|
+
}[];
|
|
35
|
+
export declare function mergeZedSchemas(existing: string, incoming: string): string;
|
|
36
|
+
export type LocalSpicedbOwners = Record<string, string>;
|
|
37
|
+
export declare const LOCAL_SPICEDB_OWNERS_SECRET = "mesh/local/dev/spicedb/schema-owners";
|
|
38
|
+
export interface LocalSpicedbConflict {
|
|
39
|
+
type: string;
|
|
40
|
+
owner: string;
|
|
41
|
+
}
|
|
42
|
+
export type LocalSpicedbSchemaPlan = {
|
|
43
|
+
ok: true;
|
|
44
|
+
schema: string;
|
|
45
|
+
owners: LocalSpicedbOwners;
|
|
46
|
+
changed: boolean;
|
|
47
|
+
} | {
|
|
48
|
+
ok: false;
|
|
49
|
+
conflicts: LocalSpicedbConflict[];
|
|
50
|
+
};
|
|
51
|
+
export declare function planLocalSpicedbSchema(input: {
|
|
52
|
+
existing: string;
|
|
53
|
+
incoming: string;
|
|
54
|
+
owners: LocalSpicedbOwners;
|
|
55
|
+
app: string;
|
|
56
|
+
}): LocalSpicedbSchemaPlan;
|
|
57
|
+
export declare class LocalSpicedbConflictError extends Error {
|
|
58
|
+
readonly app: string;
|
|
59
|
+
readonly conflicts: LocalSpicedbConflict[];
|
|
60
|
+
constructor(app: string, conflicts: LocalSpicedbConflict[]);
|
|
61
|
+
}
|
|
62
|
+
export declare function zedOf(value: unknown): string;
|
|
63
|
+
export interface LocalSpicedbIo {
|
|
64
|
+
readSchema(): Promise<string>;
|
|
65
|
+
writeSchema(schema: string): Promise<void>;
|
|
66
|
+
readOwners(): Promise<LocalSpicedbOwners>;
|
|
67
|
+
writeOwners(owners: LocalSpicedbOwners): Promise<void>;
|
|
68
|
+
writeSeed(updates: unknown[]): Promise<void>;
|
|
69
|
+
register(): Promise<void>;
|
|
70
|
+
}
|
|
71
|
+
export declare function localSpicedbIo(tenant: string, awsConfig: object): LocalSpicedbIo;
|
|
72
|
+
export declare function writeLocalSpicedbSchema(app: string, zed: string, io: LocalSpicedbIo): Promise<boolean>;
|
|
73
|
+
export interface LocalSpicedbConnection {
|
|
74
|
+
instanceRefs: LocalSpicedbRef[];
|
|
75
|
+
env: Record<string, string>;
|
|
76
|
+
notes: string[];
|
|
77
|
+
}
|
|
78
|
+
export declare function connectLocalSpicedb(input: {
|
|
79
|
+
app: string;
|
|
80
|
+
tenant: string;
|
|
81
|
+
schema: () => Promise<unknown>;
|
|
82
|
+
seed?: () => Promise<unknown>;
|
|
83
|
+
io: LocalSpicedbIo;
|
|
84
|
+
}): Promise<LocalSpicedbConnection>;
|
|
85
|
+
export declare function registerLocalSpicedb(tenant: string, awsConfig: object): Promise<void>;
|
|
86
|
+
export interface LocalSeedRelationship {
|
|
87
|
+
resource: string;
|
|
88
|
+
relation: string;
|
|
89
|
+
subject: string;
|
|
90
|
+
}
|
|
91
|
+
export declare function seedUpdates(value: unknown): {
|
|
92
|
+
updates: unknown[];
|
|
93
|
+
problems: string[];
|
|
94
|
+
};
|
|
95
|
+
export declare function writeLocalSpicedbSeed(updates: unknown[]): Promise<void>;
|