@mondaydotcomorg/z2h-cli 0.34.0 → 0.34.2
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/CHANGELOG.md +2969 -0
- package/dist/backend/__tests__/ast.test.d.ts +2 -0
- package/dist/backend/__tests__/ast.test.d.ts.map +1 -0
- package/dist/backend/__tests__/parse.test.d.ts +2 -0
- package/dist/backend/__tests__/parse.test.d.ts.map +1 -0
- package/dist/backend/ast.d.ts +41 -0
- package/dist/backend/ast.d.ts.map +1 -0
- package/dist/backend/ast.js +152 -0
- package/dist/backend/handler-declaration.d.ts +17 -0
- package/dist/backend/handler-declaration.d.ts.map +1 -0
- package/dist/backend/handler-declaration.js +83 -0
- package/dist/backend/messages.d.ts +10 -0
- package/dist/backend/messages.d.ts.map +1 -0
- package/dist/backend/messages.js +14 -0
- package/dist/backend/parse.d.ts +11 -0
- package/dist/backend/parse.d.ts.map +1 -0
- package/dist/backend/parse.js +66 -0
- package/dist/backend/rules/__tests__/snowflake-static-sql.test.d.ts +2 -0
- package/dist/backend/rules/__tests__/snowflake-static-sql.test.d.ts.map +1 -0
- package/dist/backend/rules/index.d.ts +5 -0
- package/dist/backend/rules/index.d.ts.map +1 -0
- package/dist/backend/rules/index.js +8 -0
- package/dist/backend/rules/snowflake-static-sql.d.ts +15 -0
- package/dist/backend/rules/snowflake-static-sql.d.ts.map +1 -0
- package/dist/backend/rules/snowflake-static-sql.js +75 -0
- package/dist/backend/rules/types.d.ts +29 -0
- package/dist/backend/rules/types.d.ts.map +1 -0
- package/dist/backend/rules/types.js +1 -0
- package/dist/commands/__tests__/delete.test.d.ts +2 -0
- package/dist/commands/__tests__/delete.test.d.ts.map +1 -0
- package/dist/commands/backend.d.ts +0 -1
- package/dist/commands/backend.d.ts.map +1 -1
- package/dist/commands/backend.js +6 -6
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +16 -13
- package/dist/constants.d.ts +2 -13
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +60 -45
- package/dist/esm/backend/__tests__/ast.test.d.ts +2 -0
- package/dist/esm/backend/__tests__/ast.test.d.ts.map +1 -0
- package/dist/esm/backend/__tests__/parse.test.d.ts +2 -0
- package/dist/esm/backend/__tests__/parse.test.d.ts.map +1 -0
- package/dist/esm/backend/ast.d.ts +41 -0
- package/dist/esm/backend/ast.d.ts.map +1 -0
- package/dist/esm/backend/ast.mjs +146 -0
- package/dist/esm/backend/handler-declaration.d.ts +17 -0
- package/dist/esm/backend/handler-declaration.d.ts.map +1 -0
- package/dist/esm/backend/handler-declaration.mjs +78 -0
- package/dist/esm/backend/messages.d.ts +10 -0
- package/dist/esm/backend/messages.d.ts.map +1 -0
- package/dist/esm/backend/messages.mjs +12 -0
- package/dist/esm/backend/parse.d.ts +11 -0
- package/dist/esm/backend/parse.d.ts.map +1 -0
- package/dist/esm/backend/parse.mjs +64 -0
- package/dist/esm/backend/rules/__tests__/snowflake-static-sql.test.d.ts +2 -0
- package/dist/esm/backend/rules/__tests__/snowflake-static-sql.test.d.ts.map +1 -0
- package/dist/esm/backend/rules/index.d.ts +5 -0
- package/dist/esm/backend/rules/index.d.ts.map +1 -0
- package/dist/esm/backend/rules/index.mjs +6 -0
- package/dist/esm/backend/rules/snowflake-static-sql.d.ts +15 -0
- package/dist/esm/backend/rules/snowflake-static-sql.d.ts.map +1 -0
- package/dist/esm/backend/rules/snowflake-static-sql.mjs +73 -0
- package/dist/esm/backend/rules/types.d.ts +29 -0
- package/dist/esm/backend/rules/types.d.ts.map +1 -0
- package/dist/esm/backend/rules/types.mjs +1 -0
- package/dist/esm/commands/__tests__/delete.test.d.ts +2 -0
- package/dist/esm/commands/__tests__/delete.test.d.ts.map +1 -0
- package/dist/esm/commands/backend.d.ts +0 -1
- package/dist/esm/commands/backend.d.ts.map +1 -1
- package/dist/esm/commands/backend.mjs +5 -5
- package/dist/esm/commands/deploy.d.ts.map +1 -1
- package/dist/esm/commands/deploy.mjs +9 -6
- package/dist/esm/constants.d.ts +2 -13
- package/dist/esm/constants.d.ts.map +1 -1
- package/dist/esm/constants.mjs +5 -35
- package/dist/esm/util/__tests__/usage-upload.test.d.ts +2 -0
- package/dist/esm/util/__tests__/usage-upload.test.d.ts.map +1 -0
- package/dist/esm/util/app-name.mjs +1 -1
- package/dist/esm/util/auth/__tests__/index.test.d.ts +2 -0
- package/dist/esm/util/auth/__tests__/index.test.d.ts.map +1 -0
- package/dist/esm/util/auth/broker-credential-provider.d.ts +6 -1
- package/dist/esm/util/auth/broker-credential-provider.d.ts.map +1 -1
- package/dist/esm/util/auth/broker-credential-provider.mjs +2 -2
- package/dist/esm/util/auth/index.d.ts +3 -0
- package/dist/esm/util/auth/index.d.ts.map +1 -0
- package/dist/esm/util/auth/index.mjs +2 -0
- package/dist/esm/util/broker/app.d.ts +0 -1
- package/dist/esm/util/broker/app.d.ts.map +1 -1
- package/dist/esm/util/broker/app.mjs +3 -4
- package/dist/esm/util/git/repo.mjs +1 -1
- package/dist/esm/util/s3/client.mjs +1 -1
- package/dist/esm/util/s3/upload.mjs +1 -1
- package/dist/esm/util/usage-json.d.ts +2 -2
- package/dist/esm/util/usage-json.d.ts.map +1 -1
- package/dist/esm/util/usage-json.mjs +5 -2
- package/dist/esm/util/usage-upload.d.ts +3 -0
- package/dist/esm/util/usage-upload.d.ts.map +1 -0
- package/dist/esm/util/usage-upload.mjs +29 -0
- package/dist/util/__tests__/usage-upload.test.d.ts +2 -0
- package/dist/util/__tests__/usage-upload.test.d.ts.map +1 -0
- package/dist/util/app-name.js +6 -6
- package/dist/util/auth/__tests__/index.test.d.ts +2 -0
- package/dist/util/auth/__tests__/index.test.d.ts.map +1 -0
- package/dist/util/auth/broker-credential-provider.d.ts +6 -1
- package/dist/util/auth/broker-credential-provider.d.ts.map +1 -1
- package/dist/util/auth/broker-credential-provider.js +2 -2
- package/dist/util/auth/index.d.ts +3 -0
- package/dist/util/auth/index.d.ts.map +1 -0
- package/dist/util/auth/index.js +11 -0
- package/dist/util/broker/app.d.ts +0 -1
- package/dist/util/broker/app.d.ts.map +1 -1
- package/dist/util/broker/app.js +3 -4
- package/dist/util/git/repo.js +2 -2
- package/dist/util/s3/client.js +2 -2
- package/dist/util/s3/upload.js +2 -2
- package/dist/util/usage-json.d.ts +2 -2
- package/dist/util/usage-json.d.ts.map +1 -1
- package/dist/util/usage-json.js +5 -2
- package/dist/util/usage-upload.d.ts +3 -0
- package/dist/util/usage-upload.d.ts.map +1 -0
- package/dist/util/usage-upload.js +31 -0
- package/package.json +3 -3
- package/src/commands/__tests__/backend-deploy.test.ts +2 -4
- package/src/commands/__tests__/deploy.test.ts +43 -11
- package/src/commands/backend.ts +4 -5
- package/src/commands/deploy.ts +9 -5
- package/src/constants.ts +25 -47
- package/src/util/__tests__/usage-upload.test.ts +58 -0
- package/src/util/auth/__tests__/broker-credential-provider.test.ts +4 -4
- package/src/util/auth/broker-credential-provider.ts +4 -4
- package/src/util/broker/app.ts +2 -15
- package/src/util/usage-json.ts +11 -4
- package/src/util/usage-upload.ts +38 -0
package/dist/commands/backend.js
CHANGED
|
@@ -10,7 +10,7 @@ const util_machineIdentity = require('../util/machine-identity.js');
|
|
|
10
10
|
const backend_handlers = require('../backend/handlers.js');
|
|
11
11
|
const backend_detectIntegrations = require('../backend/detect-integrations.js');
|
|
12
12
|
const util_s3_client = require('../util/s3/client.js');
|
|
13
|
-
const
|
|
13
|
+
const z2hSharedUtils = require('@mondaydotcomorg/z2h-shared-utils');
|
|
14
14
|
const backend_client = require('../backend/client.js');
|
|
15
15
|
const backend_formatSandboxRun = require('../backend/format-sandbox-run.js');
|
|
16
16
|
const backend_validate = require('../backend/validate.js');
|
|
@@ -30,23 +30,23 @@ function currentAppName() {
|
|
|
30
30
|
}
|
|
31
31
|
async function readDetectAndUpload(appDir, prefix, appName, version, deployedBy, logLabel) {
|
|
32
32
|
if (!util_usageJson.hasHandlers(appDir)) {
|
|
33
|
-
return { integrations: [], handlerNames: []
|
|
33
|
+
return { integrations: [], handlerNames: [] };
|
|
34
34
|
}
|
|
35
35
|
util_logger.info(`reading backend handlers ${logLabel}`);
|
|
36
|
-
const { handlers, apiDomains
|
|
36
|
+
const { handlers, apiDomains } = await backend_handlers.readHandlers(appDir);
|
|
37
37
|
const integrations = backend_detectIntegrations.detectIntegrations(apiDomains);
|
|
38
38
|
const handlerNames = Object.keys(handlers);
|
|
39
39
|
if (Object.keys(handlers).length === 0) {
|
|
40
|
-
return { integrations, handlerNames
|
|
40
|
+
return { integrations, handlerNames };
|
|
41
41
|
}
|
|
42
42
|
const s3 = util_s3_client.getS3Client();
|
|
43
43
|
const meta = JSON.stringify({ version, deployedBy, handlers: Object.keys(handlers) });
|
|
44
|
-
const put = (key, body, contentType) => s3.send(new clientS3.PutObjectCommand({ Bucket:
|
|
44
|
+
const put = (key, body, contentType) => s3.send(new clientS3.PutObjectCommand({ Bucket: z2hSharedUtils.BUCKET_WRITE_NAME, Key: key, Body: body, ContentType: contentType }));
|
|
45
45
|
await Promise.all([
|
|
46
46
|
...Object.entries(handlers).map(([name, code]) => put(`${prefix}/${name}.js`, code, 'application/javascript')),
|
|
47
47
|
put(`${prefix}/meta.json`, meta, 'application/json'),
|
|
48
48
|
]);
|
|
49
|
-
return { integrations, handlerNames
|
|
49
|
+
return { integrations, handlerNames };
|
|
50
50
|
}
|
|
51
51
|
/**
|
|
52
52
|
* Integration sync note: the returned set is re-derived from the CURRENT backend
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/commands/deploy.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"deploy.d.ts","sourceRoot":"","sources":["../../src/commands/deploy.ts"],"names":[],"mappings":"AAoBA,OAAO,EAAE,KAAK,UAAU,EAA2C,MAAM,4BAA4B,CAAC;AAatG,MAAM,WAAW,aAAa;IAC5B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IAIrB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAWD,wBAAsB,aAAa,CAAC,IAAI,GAAE,aAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAyB3E"}
|
package/dist/commands/deploy.js
CHANGED
|
@@ -12,6 +12,7 @@ const util_auth_authStore = require('../util/auth/auth-store.js');
|
|
|
12
12
|
const util_appName = require('../util/app-name.js');
|
|
13
13
|
const util_git_repo = require('../util/git/repo.js');
|
|
14
14
|
const util_usageJson = require('../util/usage-json.js');
|
|
15
|
+
const util_usageUpload = require('../util/usage-upload.js');
|
|
15
16
|
const util_git_gitEnv = require('../util/git/git-env.js');
|
|
16
17
|
const util_git_remoteOptions = require('../util/git/remote-options.js');
|
|
17
18
|
const util_s3_client = require('../util/s3/client.js');
|
|
@@ -23,6 +24,7 @@ const util_errors = require('../util/errors.js');
|
|
|
23
24
|
const commands_backend = require('./backend.js');
|
|
24
25
|
const commands_build = require('./build.js');
|
|
25
26
|
const commands_tag = require('./tag.js');
|
|
27
|
+
const z2hSharedUtils = require('@mondaydotcomorg/z2h-shared-utils');
|
|
26
28
|
|
|
27
29
|
const _interopDefault = e => e && e.__esModule ? e : { default: e };
|
|
28
30
|
|
|
@@ -88,7 +90,7 @@ async function uploadAndRegister(opts) {
|
|
|
88
90
|
const { paths, keyPrefix, appName, token, nextVersion, entry, gitRemote, isPreview, description, masterAppName } = opts;
|
|
89
91
|
// Runs before the frontend upload so a `deployBackend` failure can't leave a
|
|
90
92
|
// preview's unversioned `MF` dir overwritten with no rollback.
|
|
91
|
-
const { integrations, handlerNames
|
|
93
|
+
const { integrations, handlerNames } = await commands_backend.deployBackend({
|
|
92
94
|
appDir: process.cwd(),
|
|
93
95
|
appName,
|
|
94
96
|
mfKeyPrefix: keyPrefix,
|
|
@@ -97,7 +99,7 @@ async function uploadAndRegister(opts) {
|
|
|
97
99
|
isPreview,
|
|
98
100
|
});
|
|
99
101
|
try {
|
|
100
|
-
util_logger.info(`uploading ${isPreview ? 'preview ' : ''}build → s3://${
|
|
102
|
+
util_logger.info(`uploading ${isPreview ? 'preview ' : ''}build → s3://${z2hSharedUtils.BUCKET_WRITE_NAME}/${keyPrefix}/`);
|
|
101
103
|
await util_s3_upload.uploadDir(paths.shadowBuild, keyPrefix);
|
|
102
104
|
await util_broker_app.registerOrUpdateApp({
|
|
103
105
|
appName,
|
|
@@ -107,7 +109,6 @@ async function uploadAndRegister(opts) {
|
|
|
107
109
|
gitRemote,
|
|
108
110
|
integrations,
|
|
109
111
|
handlerNames,
|
|
110
|
-
apiUsages,
|
|
111
112
|
description,
|
|
112
113
|
masterAppName,
|
|
113
114
|
});
|
|
@@ -135,13 +136,13 @@ async function deployPreview({ paths, consumerName, appName, token, opts }) {
|
|
|
135
136
|
const { previewId } = await shadow_prepare.resolvePortAndMetadata(paths, util_appName.cleanAppName(consumerName));
|
|
136
137
|
const previewSlug = util_appName.buildPreviewSlug(consumerName, previewId);
|
|
137
138
|
const previewAppName = util_appName.mfAppName(previewSlug);
|
|
138
|
-
const keyPrefix = `${
|
|
139
|
+
const keyPrefix = `${z2hSharedUtils.S3_PREVIEWS_FOLDER}/${previewAppName}/MF`;
|
|
139
140
|
// Full CDN URL, not a relative path — trident-skeleton uses a manifest
|
|
140
141
|
// entry's `url` verbatim as the asset base, never joined with its own mfUrl.
|
|
141
|
-
const url = `${
|
|
142
|
+
const url = `${z2hSharedUtils.BUCKET_READ_DNS_URL}/${keyPrefix}`;
|
|
142
143
|
// No catch-all: every stage below tags its own DeployError reason at the throw site,
|
|
143
144
|
// and anything unclassified reports as `unknown` via reasonOf() in runCommand.
|
|
144
|
-
const nextVersion = (await util_auth_brokerCredentialProvider.fetchDeployVersion(previewAppName)) + 1;
|
|
145
|
+
const nextVersion = (await util_auth_brokerCredentialProvider.fetchDeployVersion(previewAppName)).version + 1;
|
|
145
146
|
util_logger.info('building');
|
|
146
147
|
const entry = await buildAndStamp({
|
|
147
148
|
paths,
|
|
@@ -173,7 +174,7 @@ async function deployPreview({ paths, consumerName, appName, token, opts }) {
|
|
|
173
174
|
appName,
|
|
174
175
|
previewId,
|
|
175
176
|
previewAppName,
|
|
176
|
-
bucket:
|
|
177
|
+
bucket: z2hSharedUtils.BUCKET_WRITE_NAME,
|
|
177
178
|
keyPrefix,
|
|
178
179
|
url,
|
|
179
180
|
previewUrl,
|
|
@@ -206,9 +207,10 @@ async function deployLive({ paths, consumerName, appName, token, opts }) {
|
|
|
206
207
|
await util_git_repo.initRepo(process.cwd(), remote);
|
|
207
208
|
gitRemote = remote;
|
|
208
209
|
}
|
|
209
|
-
const version = await util_auth_brokerCredentialProvider.fetchDeployVersion(appName);
|
|
210
|
+
const { version, id: appId } = await util_auth_brokerCredentialProvider.fetchDeployVersion(appName);
|
|
210
211
|
const nextVersion = version + 1;
|
|
211
212
|
const gitEnv = await util_git_gitEnv.resolveGitEnv(appName, gitRemote);
|
|
213
|
+
let usage = {};
|
|
212
214
|
// Sync git first so a divergence (GitConflictError) stops us.
|
|
213
215
|
// The skill commits the working tree (with an LLM-authored message) before
|
|
214
216
|
// invoking deploy, so the tree should be clean here.
|
|
@@ -217,7 +219,7 @@ async function deployLive({ paths, consumerName, appName, token, opts }) {
|
|
|
217
219
|
await util_git_repo.guardCleanTree(process.cwd());
|
|
218
220
|
util_logger.info('syncing with git remote');
|
|
219
221
|
await util_git_repo.pullAndResolve(process.cwd(), gitEnv);
|
|
220
|
-
await util_usageJson.updateOrCreateUsageJson(process.cwd(), appName, util_machineIdentity.whoAmI());
|
|
222
|
+
usage = await util_usageJson.updateOrCreateUsageJson(process.cwd(), appName, util_machineIdentity.whoAmI());
|
|
221
223
|
}
|
|
222
224
|
catch (err) {
|
|
223
225
|
throw util_errors.tagDeployError('git_error', err);
|
|
@@ -225,16 +227,16 @@ async function deployLive({ paths, consumerName, appName, token, opts }) {
|
|
|
225
227
|
}
|
|
226
228
|
util_logger.info('reading current Z2H manifest');
|
|
227
229
|
const keyPrefix = `${appName}/${nextVersion}`;
|
|
228
|
-
const url = `${
|
|
230
|
+
const url = `${z2hSharedUtils.BUCKET_READ_DNS_URL}/${keyPrefix}`;
|
|
229
231
|
util_logger.info('building');
|
|
230
232
|
const entry = await buildAndStamp({ paths, publicUrl: url, nextVersion, gitRemote, prebuiltDir: opts.prebuiltDir });
|
|
231
233
|
if (opts.dryRun) {
|
|
232
|
-
util_logger.output(`[z2h-cli] dry-run: would upload to s3://${
|
|
234
|
+
util_logger.output(`[z2h-cli] dry-run: would upload to s3://${z2hSharedUtils.BUCKET_WRITE_NAME}/${keyPrefix}/ as v${version}`, {
|
|
233
235
|
ok: true,
|
|
234
236
|
dryRun: true,
|
|
235
237
|
appName,
|
|
236
238
|
version,
|
|
237
|
-
bucket:
|
|
239
|
+
bucket: z2hSharedUtils.BUCKET_WRITE_NAME,
|
|
238
240
|
keyPrefix,
|
|
239
241
|
url,
|
|
240
242
|
entry,
|
|
@@ -274,6 +276,7 @@ async function deployLive({ paths, consumerName, appName, token, opts }) {
|
|
|
274
276
|
util_logger.info('releasing deploy lock');
|
|
275
277
|
await releaseLockBestEffort(appName, token);
|
|
276
278
|
}
|
|
279
|
+
await util_usageUpload.putAppUsage(appName, appId, usage, nextVersion);
|
|
277
280
|
// Tags are a post-deploy concern: the S3 upload has already succeeded, so a
|
|
278
281
|
// tag failure never fails the deploy (handled inside).
|
|
279
282
|
await handleDeployTags(appName);
|
|
@@ -285,7 +288,7 @@ async function deployLive({ paths, consumerName, appName, token, opts }) {
|
|
|
285
288
|
ok: true,
|
|
286
289
|
appName,
|
|
287
290
|
version: nextVersion,
|
|
288
|
-
bucket:
|
|
291
|
+
bucket: z2hSharedUtils.BUCKET_WRITE_NAME,
|
|
289
292
|
keyPrefix,
|
|
290
293
|
url,
|
|
291
294
|
liveUrl,
|
package/dist/constants.d.ts
CHANGED
|
@@ -8,19 +8,7 @@ export declare const SHADOW_DEV_DEPS: Record<string, string>;
|
|
|
8
8
|
export declare const MIN_PORT = 13000;
|
|
9
9
|
export declare const MAX_PORT = 19999;
|
|
10
10
|
export declare const GITIGNORE_ENTRIES: string[];
|
|
11
|
-
export
|
|
12
|
-
export declare const REGION = "us-east-1";
|
|
13
|
-
export declare const BUCKET_WRITE_URL = "https://prod-use1-bigbrain-zth-mf-assets.s3.us-east-1.amazonaws.com";
|
|
14
|
-
export declare const BUCKET_READ_DNS_NAME = "bigbrain-zth-mf-assets";
|
|
15
|
-
export declare const BUCKET_READ_DNS_URL = "https://bigbrain-zth-mf-assets.bigbrain.me";
|
|
16
|
-
export declare const S3_PREVIEWS_FOLDER = "previews";
|
|
17
|
-
export declare const MANIFEST_KEY = "mf-assets";
|
|
18
|
-
export declare const MANIFEST_READ_URL = "https://bigbrain-zth-mf-assets.bigbrain.me/mf-assets";
|
|
19
|
-
export declare const S3_SKILLS_BUCKET_NAME = "prod-use1-bigbrain-zth-skills";
|
|
20
|
-
export declare const DATAVIZ_SKILLS_PREFIX = "dataviz/";
|
|
21
|
-
export declare const APP_NAME_PATTERN: RegExp;
|
|
22
|
-
export declare const PREVIEW_APP_NAME_PREFIX = "zth-preview-";
|
|
23
|
-
export { ALWAYS_ON_CHANNELS, DECLARED_INTEGRATIONS, type DeclaredIntegration } from '@mondaydotcomorg/z2h-shared-utils';
|
|
11
|
+
export { ALWAYS_ON_CHANNELS, APP_USAGE_BUCKET_NAME, appUsageFolder, APP_NAME_PATTERN, BUCKET_READ_DNS_NAME, BUCKET_READ_DNS_URL, BUCKET_WRITE_NAME, BUCKET_WRITE_URL, DATAVIZ_SKILLS_PREFIX, DECLARED_INTEGRATIONS, MANIFEST_KEY, MANIFEST_READ_URL, PREVIEW_APP_NAME_PREFIX, REGION, S3_PREVIEWS_FOLDER, S3_SKILLS_BUCKET_NAME, type DeclaredIntegration, } from '@mondaydotcomorg/z2h-shared-utils';
|
|
24
12
|
export declare const DEFAULT_BROKER_BASE_URL = "https://bigbrain-zth.bigbrain.me";
|
|
25
13
|
/**
|
|
26
14
|
* Resolves the broker origin (no trailing slash). Honors
|
|
@@ -28,6 +16,7 @@ export declare const DEFAULT_BROKER_BASE_URL = "https://bigbrain-zth.bigbrain.me
|
|
|
28
16
|
* STS credential provider and the npm-broker registry URL.
|
|
29
17
|
*/
|
|
30
18
|
export declare function brokerBaseUrl(): string;
|
|
19
|
+
export declare function isProdBroker(): boolean;
|
|
31
20
|
export declare function routingHeaders(): Record<string, string>;
|
|
32
21
|
export declare const NPM_BROKER_PATH = "/z2h-cli/npm";
|
|
33
22
|
export declare const BROKER_NPM_SCOPE = "@mondaydotcomorg";
|
package/dist/constants.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,eAAO,MAAM,eAAe,SAAS,CAAC;AAGtC,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAEjD,CAAC;AAKF,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAElD,CAAC;AAMF,eAAO,MAAM,QAAQ,QAAQ,CAAC;AAC9B,eAAO,MAAM,QAAQ,QAAQ,CAAC;AAG9B,eAAO,MAAM,iBAAiB,UAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,eAAO,MAAM,eAAe,SAAS,CAAC;AAGtC,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAEjD,CAAC;AAKF,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAElD,CAAC;AAMF,eAAO,MAAM,QAAQ,QAAQ,CAAC;AAC9B,eAAO,MAAM,QAAQ,QAAQ,CAAC;AAG9B,eAAO,MAAM,iBAAiB,UAAY,CAAC;AAI3C,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,cAAc,EACd,gBAAgB,EAChB,oBAAoB,EACpB,mBAAmB,EACnB,iBAAiB,EACjB,gBAAgB,EAChB,qBAAqB,EACrB,qBAAqB,EACrB,YAAY,EACZ,iBAAiB,EACjB,uBAAuB,EACvB,MAAM,EACN,kBAAkB,EAClB,qBAAqB,EACrB,KAAK,mBAAmB,GACzB,MAAM,mCAAmC,CAAC;AAK3C,eAAO,MAAM,uBAAuB,qCAAqC,CAAC;AAE1E;;;;GAIG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED,wBAAgB,YAAY,IAAI,OAAO,CAEtC;AAID,wBAAgB,cAAc,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAGvD;AAKD,eAAO,MAAM,eAAe,iBAAiB,CAAC;AAG9C,eAAO,MAAM,gBAAgB,qBAAqB,CAAC;AAGnD,eAAO,MAAM,uBAAuB,gCAAgC,CAAC;AAMrE,eAAO,MAAM,iBAAiB,EAAG,eAAwB,CAAC;AAE1D;;;;;GAKG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C"}
|
package/dist/constants.js
CHANGED
|
@@ -26,39 +26,6 @@ const MIN_PORT = 13000;
|
|
|
26
26
|
const MAX_PORT = 19999;
|
|
27
27
|
// ─────────── Gitignore entries auto-appended to the consumer's file ────
|
|
28
28
|
const GITIGNORE_ENTRIES = ['.zth/'];
|
|
29
|
-
// ─────────── Z2H deploy bucket / contract ─────────
|
|
30
|
-
// Source of truth for the bucket layout. The CLI uses these when configuring
|
|
31
|
-
// the S3 client + uploading; bigbrain-zth's STS broker imports them via
|
|
32
|
-
// `@mondaydotcomorg/z2h-cli/constants` to scope the per-deploy session
|
|
33
|
-
// policy to the same bucket + manifest key.
|
|
34
|
-
const BUCKET_WRITE_NAME = 'prod-use1-bigbrain-zth-mf-assets';
|
|
35
|
-
const REGION = 'us-east-1';
|
|
36
|
-
const BUCKET_WRITE_URL = `https://${BUCKET_WRITE_NAME}.s3.${REGION}.amazonaws.com`;
|
|
37
|
-
const BUCKET_READ_DNS_NAME = 'bigbrain-zth-mf-assets';
|
|
38
|
-
const BUCKET_READ_DNS_URL = `https://${BUCKET_READ_DNS_NAME}.bigbrain.me`;
|
|
39
|
-
// Root prefix for ephemeral preview uploads: `previews/<previewAppName>/MF/...`,
|
|
40
|
-
// where previewAppName is the preview's own `mf-zth-preview-<id>-<app>` name.
|
|
41
|
-
// Shared by the CLI (upload path) and bigbrain-zth (STS policy + manifest overlay).
|
|
42
|
-
const S3_PREVIEWS_FOLDER = 'previews';
|
|
43
|
-
// No `.json` extension — TridentSkeleton's `mfUrl` API appends `/mf-assets`
|
|
44
|
-
// to the bucket base when fetching, so the manifest must live at this exact
|
|
45
|
-
// key. See microfrontends/mf-bigbrain-zth/.../ZeroToHeroHost.tsx.
|
|
46
|
-
const MANIFEST_KEY = 'mf-assets';
|
|
47
|
-
const MANIFEST_READ_URL = `${BUCKET_READ_DNS_URL}/${MANIFEST_KEY}`;
|
|
48
|
-
// ─────────── Skills bucket (read-only) ─────────
|
|
49
|
-
// bigbrain-zth mints read-only STS creds scoped to this bucket (mintDatavizSkillsCredentials);
|
|
50
|
-
// bigbrain-zth-agent syncs from it into its vendor/ at pod startup (syncDatavizVendor).
|
|
51
|
-
// Both import from here so the two sides can't drift.
|
|
52
|
-
const S3_SKILLS_BUCKET_NAME = 'prod-use1-bigbrain-zth-skills';
|
|
53
|
-
// Prefix the dataviz design-system skills are published under
|
|
54
|
-
// (by data-cookbook's own CI on merge to master).
|
|
55
|
-
const DATAVIZ_SKILLS_PREFIX = 'dataviz/';
|
|
56
|
-
// ─────────── App-name slug — backend & CLI both honor this ─────
|
|
57
|
-
// Lowercase kebab-case, must start with a letter, 2-50 chars total. The
|
|
58
|
-
// backend STS broker rejects anything else with 400; the CLI can validate
|
|
59
|
-
// upfront for friendlier errors.
|
|
60
|
-
const APP_NAME_PATTERN = /^[a-z][a-z0-9-]{1,49}$/;
|
|
61
|
-
const PREVIEW_APP_NAME_PREFIX = 'zth-preview-';
|
|
62
29
|
// ─────────── Broker origin + npm registry (shared §3 contract) ─────
|
|
63
30
|
// The bigbrain-zth broker fronts both the STS credential route and the npm
|
|
64
31
|
// proxy. `Z2H_BROKER_BASE_URL` overrides the origin for tests/staging.
|
|
@@ -71,6 +38,9 @@ const DEFAULT_BROKER_BASE_URL = 'https://bigbrain-zth.bigbrain.me';
|
|
|
71
38
|
function brokerBaseUrl() {
|
|
72
39
|
return process.env.Z2H_BROKER_BASE_URL || DEFAULT_BROKER_BASE_URL;
|
|
73
40
|
}
|
|
41
|
+
function isProdBroker() {
|
|
42
|
+
return brokerBaseUrl() === DEFAULT_BROKER_BASE_URL;
|
|
43
|
+
}
|
|
74
44
|
// Returns Baggage header for monday-mirror routing when Z2H_ROUTING_KEY is set.
|
|
75
45
|
// No-op in production (returns {}) — only activates when the env var is set.
|
|
76
46
|
function routingHeaders() {
|
|
@@ -104,33 +74,78 @@ Object.defineProperty(exports, 'ALWAYS_ON_CHANNELS', {
|
|
|
104
74
|
enumerable: true,
|
|
105
75
|
get: () => z2hSharedUtils.ALWAYS_ON_CHANNELS
|
|
106
76
|
});
|
|
77
|
+
Object.defineProperty(exports, 'APP_NAME_PATTERN', {
|
|
78
|
+
enumerable: true,
|
|
79
|
+
get: () => z2hSharedUtils.APP_NAME_PATTERN
|
|
80
|
+
});
|
|
81
|
+
Object.defineProperty(exports, 'APP_USAGE_BUCKET_NAME', {
|
|
82
|
+
enumerable: true,
|
|
83
|
+
get: () => z2hSharedUtils.APP_USAGE_BUCKET_NAME
|
|
84
|
+
});
|
|
85
|
+
Object.defineProperty(exports, 'BUCKET_READ_DNS_NAME', {
|
|
86
|
+
enumerable: true,
|
|
87
|
+
get: () => z2hSharedUtils.BUCKET_READ_DNS_NAME
|
|
88
|
+
});
|
|
89
|
+
Object.defineProperty(exports, 'BUCKET_READ_DNS_URL', {
|
|
90
|
+
enumerable: true,
|
|
91
|
+
get: () => z2hSharedUtils.BUCKET_READ_DNS_URL
|
|
92
|
+
});
|
|
93
|
+
Object.defineProperty(exports, 'BUCKET_WRITE_NAME', {
|
|
94
|
+
enumerable: true,
|
|
95
|
+
get: () => z2hSharedUtils.BUCKET_WRITE_NAME
|
|
96
|
+
});
|
|
97
|
+
Object.defineProperty(exports, 'BUCKET_WRITE_URL', {
|
|
98
|
+
enumerable: true,
|
|
99
|
+
get: () => z2hSharedUtils.BUCKET_WRITE_URL
|
|
100
|
+
});
|
|
101
|
+
Object.defineProperty(exports, 'DATAVIZ_SKILLS_PREFIX', {
|
|
102
|
+
enumerable: true,
|
|
103
|
+
get: () => z2hSharedUtils.DATAVIZ_SKILLS_PREFIX
|
|
104
|
+
});
|
|
107
105
|
Object.defineProperty(exports, 'DECLARED_INTEGRATIONS', {
|
|
108
106
|
enumerable: true,
|
|
109
107
|
get: () => z2hSharedUtils.DECLARED_INTEGRATIONS
|
|
110
108
|
});
|
|
111
|
-
exports
|
|
109
|
+
Object.defineProperty(exports, 'MANIFEST_KEY', {
|
|
110
|
+
enumerable: true,
|
|
111
|
+
get: () => z2hSharedUtils.MANIFEST_KEY
|
|
112
|
+
});
|
|
113
|
+
Object.defineProperty(exports, 'MANIFEST_READ_URL', {
|
|
114
|
+
enumerable: true,
|
|
115
|
+
get: () => z2hSharedUtils.MANIFEST_READ_URL
|
|
116
|
+
});
|
|
117
|
+
Object.defineProperty(exports, 'PREVIEW_APP_NAME_PREFIX', {
|
|
118
|
+
enumerable: true,
|
|
119
|
+
get: () => z2hSharedUtils.PREVIEW_APP_NAME_PREFIX
|
|
120
|
+
});
|
|
121
|
+
Object.defineProperty(exports, 'REGION', {
|
|
122
|
+
enumerable: true,
|
|
123
|
+
get: () => z2hSharedUtils.REGION
|
|
124
|
+
});
|
|
125
|
+
Object.defineProperty(exports, 'S3_PREVIEWS_FOLDER', {
|
|
126
|
+
enumerable: true,
|
|
127
|
+
get: () => z2hSharedUtils.S3_PREVIEWS_FOLDER
|
|
128
|
+
});
|
|
129
|
+
Object.defineProperty(exports, 'S3_SKILLS_BUCKET_NAME', {
|
|
130
|
+
enumerable: true,
|
|
131
|
+
get: () => z2hSharedUtils.S3_SKILLS_BUCKET_NAME
|
|
132
|
+
});
|
|
133
|
+
Object.defineProperty(exports, 'appUsageFolder', {
|
|
134
|
+
enumerable: true,
|
|
135
|
+
get: () => z2hSharedUtils.appUsageFolder
|
|
136
|
+
});
|
|
112
137
|
exports.BROKER_NPM_SCOPE = BROKER_NPM_SCOPE;
|
|
113
|
-
exports.BUCKET_READ_DNS_NAME = BUCKET_READ_DNS_NAME;
|
|
114
|
-
exports.BUCKET_READ_DNS_URL = BUCKET_READ_DNS_URL;
|
|
115
|
-
exports.BUCKET_WRITE_NAME = BUCKET_WRITE_NAME;
|
|
116
|
-
exports.BUCKET_WRITE_URL = BUCKET_WRITE_URL;
|
|
117
|
-
exports.DATAVIZ_SKILLS_PREFIX = DATAVIZ_SKILLS_PREFIX;
|
|
118
138
|
exports.DEFAULT_BROKER_BASE_URL = DEFAULT_BROKER_BASE_URL;
|
|
119
139
|
exports.GITIGNORE_ENTRIES = GITIGNORE_ENTRIES;
|
|
120
|
-
exports.MANIFEST_KEY = MANIFEST_KEY;
|
|
121
|
-
exports.MANIFEST_READ_URL = MANIFEST_READ_URL;
|
|
122
140
|
exports.MAX_PORT = MAX_PORT;
|
|
123
141
|
exports.MIN_PORT = MIN_PORT;
|
|
124
142
|
exports.NPM_BROKER_PATH = NPM_BROKER_PATH;
|
|
125
|
-
exports.PREVIEW_APP_NAME_PREFIX = PREVIEW_APP_NAME_PREFIX;
|
|
126
143
|
exports.PUBLIC_NPM_REGISTRY_URL = PUBLIC_NPM_REGISTRY_URL;
|
|
127
|
-
exports.REGION = REGION;
|
|
128
|
-
exports.S3_PREVIEWS_FOLDER = S3_PREVIEWS_FOLDER;
|
|
129
|
-
exports.S3_SKILLS_BUCKET_NAME = S3_SKILLS_BUCKET_NAME;
|
|
130
144
|
exports.SHADOW_DEV_DEPS = SHADOW_DEV_DEPS;
|
|
131
145
|
exports.SHADOW_DIR_NAME = SHADOW_DIR_NAME;
|
|
132
146
|
exports.SHADOW_SCRIPTS = SHADOW_SCRIPTS;
|
|
133
147
|
exports.Z2H_NPM_TOKEN_ENV = Z2H_NPM_TOKEN_ENV;
|
|
134
148
|
exports.brokerBaseUrl = brokerBaseUrl;
|
|
135
149
|
exports.brokerNpmRegistryUrl = brokerNpmRegistryUrl;
|
|
150
|
+
exports.isProdBroker = isProdBroker;
|
|
136
151
|
exports.routingHeaders = routingHeaders;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ast.test.d.ts","sourceRoot":"","sources":["../../../../src/backend/__tests__/ast.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.test.d.ts","sourceRoot":"","sources":["../../../../src/backend/__tests__/parse.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { AnyNode, Expression, Node, Pattern, Program, VariableDeclaration } from 'acorn';
|
|
2
|
+
/** 1-based line a node starts on; requires the program to be parsed with `locations: true`. */
|
|
3
|
+
export declare const lineOf: (node: Node) => number | undefined;
|
|
4
|
+
export interface Declaration {
|
|
5
|
+
kind: VariableDeclaration['kind'];
|
|
6
|
+
init: Expression | null | undefined;
|
|
7
|
+
/**
|
|
8
|
+
* Property path from `init` to this binding: `[]` for `const x = init`,
|
|
9
|
+
* `['a', 'b']` for `const { a: { b: x } } = init`, `undefined` when the value
|
|
10
|
+
* is not a plain property read (array/rest/default patterns).
|
|
11
|
+
*/
|
|
12
|
+
path: string[] | undefined;
|
|
13
|
+
}
|
|
14
|
+
export interface Bindings {
|
|
15
|
+
/** Every `var|let|const <name> = …` in the file, by name. */
|
|
16
|
+
declarations: Map<string, Declaration[]>;
|
|
17
|
+
/** Names whose value cannot be pinned: reassigned, updated, or bound as parameters. */
|
|
18
|
+
unpinnable: Set<string>;
|
|
19
|
+
}
|
|
20
|
+
/** Every identifier a binding pattern introduces (`{ a, b: [c] } = …` → a, c). */
|
|
21
|
+
export declare const patternNames: (pattern: Pattern) => string[];
|
|
22
|
+
export declare function collectBindings(program: Program): Bindings;
|
|
23
|
+
export interface PathResolver {
|
|
24
|
+
/**
|
|
25
|
+
* Dotted path of a member chain, following `const` aliases back to their
|
|
26
|
+
* source: with `const sf = ctx.api.v1.snowflake`, `sf.query` resolves to
|
|
27
|
+
* `ctx.api.v1.snowflake.query`. Destructuring counts too
|
|
28
|
+
* (`const { snowflake: sf } = ctx.api.v1`). `undefined` if any link is dynamic.
|
|
29
|
+
*
|
|
30
|
+
* Only single, never-reassigned, never-shadowed `const` bindings are followed —
|
|
31
|
+
* anything else is left as written, so a `let` alias or a parameter of the same
|
|
32
|
+
* name is never mistaken for the channel. The handler's first parameter is
|
|
33
|
+
* treated as `ctx` even when renamed (`handler(context)` → `context.api.v1.db`
|
|
34
|
+
* resolves as `ctx.api.v1.db`).
|
|
35
|
+
*/
|
|
36
|
+
pathOf(node: AnyNode): string | undefined;
|
|
37
|
+
}
|
|
38
|
+
export declare function createPathResolver(bindings: Bindings, contextParam?: string): PathResolver;
|
|
39
|
+
/** Every `ctx.api.v1.<domain>` the program touches (known or not), through `paths`. */
|
|
40
|
+
export declare function collectApiDomains(program: Program, paths: PathResolver): Set<string>;
|
|
41
|
+
//# sourceMappingURL=ast.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ast.d.ts","sourceRoot":"","sources":["../../../src/backend/ast.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,mBAAmB,EAAE,MAAM,OAAO,CAAC;AAG9F,+FAA+F;AAC/F,eAAO,MAAM,MAAM,GAAI,MAAM,IAAI,KAAG,MAAM,GAAG,SAAiC,CAAC;AAI/E,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAClC,IAAI,EAAE,UAAU,GAAG,IAAI,GAAG,SAAS,CAAC;IACpC;;;;OAIG;IACH,IAAI,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;CAC5B;AAED,MAAM,WAAW,QAAQ;IACvB,6DAA6D;IAC7D,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC,CAAC;IACzC,uFAAuF;IACvF,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACzB;AA8CD,kFAAkF;AAClF,eAAO,MAAM,YAAY,GAAI,SAAS,OAAO,KAAG,MAAM,EAAmD,CAAC;AAE1G,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,QAAQ,CA4C1D;AA2BD,MAAM,WAAW,YAAY;IAC3B;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC;CAC3C;AAED,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,QAAQ,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,YAAY,CA6B1F;AAED,uFAAuF;AACvF,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,YAAY,GAAG,GAAG,CAAC,MAAM,CAAC,CAWpF"}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { full, simple } from 'acorn-walk';
|
|
2
|
+
|
|
3
|
+
/** 1-based line a node starts on; requires the program to be parsed with `locations: true`. */
|
|
4
|
+
const lineOf = (node) => node.loc?.start.line;
|
|
5
|
+
/**
|
|
6
|
+
* Every identifier a binding pattern introduces, with its property path from the
|
|
7
|
+
* pattern's value. `path` is deliberately not defaulted: callers pass `[]` for
|
|
8
|
+
* the root and `undefined` once the pattern stops being a plain property read.
|
|
9
|
+
*/
|
|
10
|
+
function patternBindings(pattern, path) {
|
|
11
|
+
switch (pattern.type) {
|
|
12
|
+
case 'Identifier':
|
|
13
|
+
return [{ name: pattern.name, path }];
|
|
14
|
+
case 'ObjectPattern':
|
|
15
|
+
return pattern.properties.flatMap(p => {
|
|
16
|
+
if (p.type === 'RestElement') {
|
|
17
|
+
return patternBindings(p.argument, undefined);
|
|
18
|
+
}
|
|
19
|
+
const key = propertyKey(p.key, p.computed);
|
|
20
|
+
return patternBindings(p.value, path && key !== undefined ? [...path, key] : undefined);
|
|
21
|
+
});
|
|
22
|
+
case 'ArrayPattern':
|
|
23
|
+
return pattern.elements.flatMap(e => (e ? patternBindings(e, undefined) : []));
|
|
24
|
+
case 'AssignmentPattern':
|
|
25
|
+
return patternBindings(pattern.left, undefined);
|
|
26
|
+
case 'RestElement':
|
|
27
|
+
return patternBindings(pattern.argument, undefined);
|
|
28
|
+
default:
|
|
29
|
+
// MemberExpression targets (`obj.x = …`) bind no names.
|
|
30
|
+
return [];
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function propertyKey(key, computed) {
|
|
34
|
+
if (key.type === 'Literal' && typeof key.value === 'string') {
|
|
35
|
+
return key.value;
|
|
36
|
+
}
|
|
37
|
+
if (!computed && key.type === 'Identifier') {
|
|
38
|
+
return key.name;
|
|
39
|
+
}
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
/** Every identifier a binding pattern introduces (`{ a, b: [c] } = …` → a, c). */
|
|
43
|
+
const patternNames = (pattern) => patternBindings(pattern, []).map(b => b.name);
|
|
44
|
+
function collectBindings(program) {
|
|
45
|
+
const declarations = new Map();
|
|
46
|
+
const unpinnable = new Set();
|
|
47
|
+
const markUnpinnable = (pattern) => patternNames(pattern).forEach(n => unpinnable.add(n));
|
|
48
|
+
full(program, node => {
|
|
49
|
+
switch (node.type) {
|
|
50
|
+
case 'VariableDeclaration':
|
|
51
|
+
for (const declarator of node.declarations) {
|
|
52
|
+
for (const { name, path } of patternBindings(declarator.id, [])) {
|
|
53
|
+
const list = declarations.get(name) ?? [];
|
|
54
|
+
list.push({ kind: node.kind, init: declarator.init, path });
|
|
55
|
+
declarations.set(name, list);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
break;
|
|
59
|
+
case 'AssignmentExpression':
|
|
60
|
+
markUnpinnable(node.left);
|
|
61
|
+
break;
|
|
62
|
+
case 'UpdateExpression':
|
|
63
|
+
if (node.argument.type === 'Identifier') {
|
|
64
|
+
unpinnable.add(node.argument.name);
|
|
65
|
+
}
|
|
66
|
+
break;
|
|
67
|
+
case 'ForInStatement':
|
|
68
|
+
case 'ForOfStatement':
|
|
69
|
+
if (node.left.type !== 'VariableDeclaration') {
|
|
70
|
+
markUnpinnable(node.left);
|
|
71
|
+
}
|
|
72
|
+
break;
|
|
73
|
+
case 'FunctionDeclaration':
|
|
74
|
+
case 'FunctionExpression':
|
|
75
|
+
case 'ArrowFunctionExpression':
|
|
76
|
+
node.params.forEach(markUnpinnable);
|
|
77
|
+
break;
|
|
78
|
+
case 'CatchClause':
|
|
79
|
+
if (node.param) {
|
|
80
|
+
markUnpinnable(node.param);
|
|
81
|
+
}
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
return { declarations, unpinnable };
|
|
86
|
+
}
|
|
87
|
+
/** `a.b.c` / `a['b'].c` → root `a`, parts `[b, c]`; `undefined` if any link is dynamic or the root is not an identifier. */
|
|
88
|
+
function memberChain(node) {
|
|
89
|
+
if (node.type === 'ChainExpression') {
|
|
90
|
+
return memberChain(node.expression);
|
|
91
|
+
}
|
|
92
|
+
const parts = [];
|
|
93
|
+
let cur = node;
|
|
94
|
+
while (cur.type === 'MemberExpression') {
|
|
95
|
+
const key = propertyKey(cur.property, cur.computed);
|
|
96
|
+
if (key === undefined) {
|
|
97
|
+
return undefined;
|
|
98
|
+
}
|
|
99
|
+
parts.unshift(key);
|
|
100
|
+
cur = cur.object;
|
|
101
|
+
}
|
|
102
|
+
return cur.type === 'Identifier' ? { root: cur.name, parts } : undefined;
|
|
103
|
+
}
|
|
104
|
+
function createPathResolver(bindings, contextParam) {
|
|
105
|
+
function resolveChain(node, resolving) {
|
|
106
|
+
const chain = memberChain(node);
|
|
107
|
+
if (!chain) {
|
|
108
|
+
return undefined;
|
|
109
|
+
}
|
|
110
|
+
return [resolveRoot(chain.root, resolving), ...chain.parts].join('.');
|
|
111
|
+
}
|
|
112
|
+
function resolveRoot(name, resolving) {
|
|
113
|
+
if (contextParam !== undefined && name === contextParam) {
|
|
114
|
+
return 'ctx';
|
|
115
|
+
}
|
|
116
|
+
if (bindings.unpinnable.has(name) || resolving.has(name)) {
|
|
117
|
+
return name;
|
|
118
|
+
}
|
|
119
|
+
const decls = bindings.declarations.get(name);
|
|
120
|
+
if (!decls || decls.length !== 1) {
|
|
121
|
+
return name;
|
|
122
|
+
}
|
|
123
|
+
const [{ kind, init, path }] = decls;
|
|
124
|
+
if (kind !== 'const' || !init || !path) {
|
|
125
|
+
return name;
|
|
126
|
+
}
|
|
127
|
+
const base = resolveChain(init, new Set(resolving).add(name));
|
|
128
|
+
return base ? [base, ...path].join('.') : name;
|
|
129
|
+
}
|
|
130
|
+
return { pathOf: node => resolveChain(node, new Set()) };
|
|
131
|
+
}
|
|
132
|
+
/** Every `ctx.api.v1.<domain>` the program touches (known or not), through `paths`. */
|
|
133
|
+
function collectApiDomains(program, paths) {
|
|
134
|
+
const apiDomains = new Set();
|
|
135
|
+
simple(program, {
|
|
136
|
+
MemberExpression(node) {
|
|
137
|
+
const [obj, api, version, domain] = paths.pathOf(node)?.split('.') ?? [];
|
|
138
|
+
if (obj === 'ctx' && api === 'api' && version === 'v1' && domain) {
|
|
139
|
+
apiDomains.add(domain);
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
});
|
|
143
|
+
return apiDomains;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export { collectApiDomains, collectBindings, createPathResolver, lineOf, patternNames };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Expression, FunctionDeclaration, ModuleDeclaration, Statement } from 'acorn';
|
|
2
|
+
export type HandlerDeclaration = {
|
|
3
|
+
kind: 'function';
|
|
4
|
+
params: FunctionDeclaration['params'];
|
|
5
|
+
} | {
|
|
6
|
+
kind: 'variable';
|
|
7
|
+
init: Expression | null | undefined;
|
|
8
|
+
};
|
|
9
|
+
/** The top-level declaration that binds `handler`, if any. */
|
|
10
|
+
export declare function findHandlerDeclaration(body: readonly (Statement | ModuleDeclaration)[]): HandlerDeclaration | undefined;
|
|
11
|
+
/** `export function handler`, `export const handler`, `export { handler }`, `export default handler`. */
|
|
12
|
+
export declare function exportsHandler(node: Statement | ModuleDeclaration): boolean;
|
|
13
|
+
/** First positional parameter of `handler`, when it's a plain identifier (`ctx`, `context`, …). */
|
|
14
|
+
export declare function handlerContextParamName(declaration: HandlerDeclaration): string | undefined;
|
|
15
|
+
/** Values that can never be a function, so `const handler = <this>` is caught at build time. */
|
|
16
|
+
export declare const NEVER_A_FUNCTION: ReadonlySet<string>;
|
|
17
|
+
//# sourceMappingURL=handler-declaration.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handler-declaration.d.ts","sourceRoot":"","sources":["../../../src/backend/handler-declaration.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAGV,UAAU,EACV,mBAAmB,EAEnB,iBAAiB,EAEjB,SAAS,EACV,MAAM,OAAO,CAAC;AAMf,MAAM,MAAM,kBAAkB,GAC1B;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,MAAM,EAAE,mBAAmB,CAAC,QAAQ,CAAC,CAAA;CAAE,GAC3D;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE,UAAU,GAAG,IAAI,GAAG,SAAS,CAAA;CAAE,CAAC;AAE9D,8DAA8D;AAC9D,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,SAAS,CAAC,SAAS,GAAG,iBAAiB,CAAC,EAAE,GAC/C,kBAAkB,GAAG,SAAS,CAahC;AAED,yGAAyG;AACzG,wBAAgB,cAAc,CAAC,IAAI,EAAE,SAAS,GAAG,iBAAiB,GAAG,OAAO,CAe3E;AAsCD,mGAAmG;AACnG,wBAAgB,uBAAuB,CAAC,WAAW,EAAE,kBAAkB,GAAG,MAAM,GAAG,SAAS,CAG3F;AAED,gGAAgG;AAChG,eAAO,MAAM,gBAAgB,EAAE,WAAW,CAAC,MAAM,CAK/C,CAAC"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/** True for the `handler` identifier specifically — used everywhere a node might name the binding. */
|
|
2
|
+
const isHandlerIdentifier = (candidate) => candidate?.type === 'Identifier' && candidate.name === 'handler';
|
|
3
|
+
/** The top-level declaration that binds `handler`, if any. */
|
|
4
|
+
function findHandlerDeclaration(body) {
|
|
5
|
+
for (const node of body) {
|
|
6
|
+
if (node.type === 'FunctionDeclaration' && isHandlerIdentifier(node.id)) {
|
|
7
|
+
return { kind: 'function', params: node.params };
|
|
8
|
+
}
|
|
9
|
+
if (node.type === 'VariableDeclaration') {
|
|
10
|
+
const declarator = node.declarations.find(d => isHandlerIdentifier(d.id));
|
|
11
|
+
if (declarator) {
|
|
12
|
+
return { kind: 'variable', init: declarator.init };
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
/** `export function handler`, `export const handler`, `export { handler }`, `export default handler`. */
|
|
19
|
+
function exportsHandler(node) {
|
|
20
|
+
if (node.type === 'ExportNamedDeclaration') {
|
|
21
|
+
return ((node.declaration != null && findHandlerDeclaration([node.declaration]) !== undefined) ||
|
|
22
|
+
node.specifiers.some(s => isHandlerIdentifier(s.local) || isHandlerIdentifier(s.exported)));
|
|
23
|
+
}
|
|
24
|
+
if (node.type === 'ExportDefaultDeclaration') {
|
|
25
|
+
const { declaration } = node;
|
|
26
|
+
return ((declaration.type === 'FunctionDeclaration' && isHandlerIdentifier(declaration.id)) ||
|
|
27
|
+
isHandlerIdentifier(declaration));
|
|
28
|
+
}
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
/** Peel `wrap(fn)`, `(0, fn)`, and the like until a function expression remains. */
|
|
32
|
+
function asFunction(expr) {
|
|
33
|
+
if (!expr) {
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
switch (expr.type) {
|
|
37
|
+
case 'FunctionExpression':
|
|
38
|
+
case 'ArrowFunctionExpression':
|
|
39
|
+
return expr;
|
|
40
|
+
case 'SequenceExpression':
|
|
41
|
+
return asFunction(expr.expressions.at(-1));
|
|
42
|
+
case 'CallExpression': {
|
|
43
|
+
for (const arg of expr.arguments) {
|
|
44
|
+
if (arg.type === 'SpreadElement') {
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
const fn = asFunction(arg);
|
|
48
|
+
if (fn) {
|
|
49
|
+
return fn;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
54
|
+
default:
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function firstParamName(params) {
|
|
59
|
+
let first = params[0];
|
|
60
|
+
if (first?.type === 'AssignmentPattern') {
|
|
61
|
+
first = first.left;
|
|
62
|
+
}
|
|
63
|
+
return first?.type === 'Identifier' ? first.name : undefined;
|
|
64
|
+
}
|
|
65
|
+
/** First positional parameter of `handler`, when it's a plain identifier (`ctx`, `context`, …). */
|
|
66
|
+
function handlerContextParamName(declaration) {
|
|
67
|
+
const params = declaration.kind === 'function' ? declaration.params : asFunction(declaration.init)?.params;
|
|
68
|
+
return params ? firstParamName(params) : undefined;
|
|
69
|
+
}
|
|
70
|
+
/** Values that can never be a function, so `const handler = <this>` is caught at build time. */
|
|
71
|
+
const NEVER_A_FUNCTION = new Set([
|
|
72
|
+
'Literal',
|
|
73
|
+
'ObjectExpression',
|
|
74
|
+
'ArrayExpression',
|
|
75
|
+
'TemplateLiteral',
|
|
76
|
+
]);
|
|
77
|
+
|
|
78
|
+
export { NEVER_A_FUNCTION, exportsHandler, findHandlerDeclaration, handlerContextParamName };
|