@mondaydotcomorg/z2h-cli 0.22.0 → 0.23.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/dist/auth.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ export { generateZ2HTokenCommand, type GenerateZ2HTokenOptions } from './commands/generate-z2h-token';
2
+ export { readZthAuth, Z2hAuthMissingError, Z2H_AUTH_FILE, type ZthAuth } from './util/auth/auth-store';
3
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,KAAK,uBAAuB,EAAE,MAAM,+BAA+B,CAAC;AACtG,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,aAAa,EAAE,KAAK,OAAO,EAAE,MAAM,wBAAwB,CAAC"}
package/dist/auth.js ADDED
@@ -0,0 +1,11 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+
3
+ const commands_generateZ2hToken = require('./commands/generate-z2h-token.js');
4
+ const util_auth_authStore = require('./util/auth/auth-store.js');
5
+
6
+
7
+
8
+ exports.generateZ2HTokenCommand = commands_generateZ2hToken.generateZ2HTokenCommand;
9
+ exports.Z2H_AUTH_FILE = util_auth_authStore.Z2H_AUTH_FILE;
10
+ exports.Z2hAuthMissingError = util_auth_authStore.Z2hAuthMissingError;
11
+ exports.readZthAuth = util_auth_authStore.readZthAuth;
@@ -0,0 +1,3 @@
1
+ export { generateZ2HTokenCommand, type GenerateZ2HTokenOptions } from './commands/generate-z2h-token';
2
+ export { readZthAuth, Z2hAuthMissingError, Z2H_AUTH_FILE, type ZthAuth } from './util/auth/auth-store';
3
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,KAAK,uBAAuB,EAAE,MAAM,+BAA+B,CAAC;AACtG,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,aAAa,EAAE,KAAK,OAAO,EAAE,MAAM,wBAAwB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { generateZ2HTokenCommand } from './commands/generate-z2h-token.mjs';
2
+ export { Z2H_AUTH_FILE, Z2hAuthMissingError, readZthAuth } from './util/auth/auth-store.mjs';
@@ -0,0 +1,3 @@
1
+ export { setupS3Client, getS3Client } from './util/s3/client';
2
+ export { uploadDir } from './util/s3/upload';
3
+ //# sourceMappingURL=s3.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"s3.d.ts","sourceRoot":"","sources":["../../src/s3.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { getS3Client, setupS3Client } from './util/s3/client.mjs';
2
+ export { uploadDir } from './util/s3/upload.mjs';
@@ -1,2 +1,2 @@
1
- export declare function uploadDir(localDir: string, keyPrefix: string): Promise<string[]>;
1
+ export declare function uploadDir(localDir: string, keyPrefix: string, bucket?: string): Promise<string[]>;
2
2
  //# sourceMappingURL=upload.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../../../../src/util/s3/upload.ts"],"names":[],"mappings":"AAeA,wBAAsB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CA0BtF"}
1
+ {"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../../../../src/util/s3/upload.ts"],"names":[],"mappings":"AAeA,wBAAsB,SAAS,CAC7B,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,MAAM,GAAE,MAA0B,GACjC,OAAO,CAAC,MAAM,EAAE,CAAC,CA0BnB"}
@@ -11,7 +11,7 @@ import { getS3Client } from './client.mjs';
11
11
  // the URL itself is the cache key. Assets never need to be revalidated.
12
12
  const FOREVER = 'public, immutable';
13
13
  const UPLOAD_CONCURRENCY = 5;
14
- async function uploadDir(localDir, keyPrefix) {
14
+ async function uploadDir(localDir, keyPrefix, bucket = BUCKET_WRITE_NAME) {
15
15
  const entries = await readdir(localDir, { recursive: true, withFileTypes: true });
16
16
  const files = entries.filter(e => e.isFile()).map(e => path.relative(localDir, path.join(e.parentPath, e.name)));
17
17
  const s3 = getS3Client();
@@ -20,7 +20,7 @@ async function uploadDir(localDir, keyPrefix) {
20
20
  const contentType = lookup(rel) || 'application/octet-stream';
21
21
  const key = `${keyPrefix}/${rel.split(path.sep).join('/')}`;
22
22
  await s3.send(new PutObjectCommand({
23
- Bucket: BUCKET_WRITE_NAME,
23
+ Bucket: bucket,
24
24
  Key: key,
25
25
  Body: body,
26
26
  ContentType: contentType,
package/dist/s3.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ export { setupS3Client, getS3Client } from './util/s3/client';
2
+ export { uploadDir } from './util/s3/upload';
3
+ //# sourceMappingURL=s3.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"s3.d.ts","sourceRoot":"","sources":["../src/s3.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC"}
package/dist/s3.js ADDED
@@ -0,0 +1,10 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+
3
+ const util_s3_client = require('./util/s3/client.js');
4
+ const util_s3_upload = require('./util/s3/upload.js');
5
+
6
+
7
+
8
+ exports.getS3Client = util_s3_client.getS3Client;
9
+ exports.setupS3Client = util_s3_client.setupS3Client;
10
+ exports.uploadDir = util_s3_upload.uploadDir;
@@ -1,2 +1,2 @@
1
- export declare function uploadDir(localDir: string, keyPrefix: string): Promise<string[]>;
1
+ export declare function uploadDir(localDir: string, keyPrefix: string, bucket?: string): Promise<string[]>;
2
2
  //# sourceMappingURL=upload.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../../../src/util/s3/upload.ts"],"names":[],"mappings":"AAeA,wBAAsB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CA0BtF"}
1
+ {"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../../../src/util/s3/upload.ts"],"names":[],"mappings":"AAeA,wBAAsB,SAAS,CAC7B,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,MAAM,GAAE,MAA0B,GACjC,OAAO,CAAC,MAAM,EAAE,CAAC,CA0BnB"}
@@ -18,7 +18,7 @@ const pMap__default = /*#__PURE__*/_interopDefault(pMap);
18
18
  // the URL itself is the cache key. Assets never need to be revalidated.
19
19
  const FOREVER = 'public, immutable';
20
20
  const UPLOAD_CONCURRENCY = 5;
21
- async function uploadDir(localDir, keyPrefix) {
21
+ async function uploadDir(localDir, keyPrefix, bucket = constants.BUCKET_WRITE_NAME) {
22
22
  const entries = await promises.readdir(localDir, { recursive: true, withFileTypes: true });
23
23
  const files = entries.filter(e => e.isFile()).map(e => path__default.default.relative(localDir, path__default.default.join(e.parentPath, e.name)));
24
24
  const s3 = util_s3_client.getS3Client();
@@ -27,7 +27,7 @@ async function uploadDir(localDir, keyPrefix) {
27
27
  const contentType = mimeTypes.lookup(rel) || 'application/octet-stream';
28
28
  const key = `${keyPrefix}/${rel.split(path__default.default.sep).join('/')}`;
29
29
  await s3.send(new clientS3.PutObjectCommand({
30
- Bucket: constants.BUCKET_WRITE_NAME,
30
+ Bucket: bucket,
31
31
  Key: key,
32
32
  Body: body,
33
33
  ContentType: contentType,
@@ -32,6 +32,15 @@ function hashQuery(boundSql: string, params: Record<string, SnowflakeParamValue>
32
32
  return createHash('sha256').update(boundSql).update('|').update(JSON.stringify(sorted)).digest('hex').slice(0, 16);
33
33
  }
34
34
 
35
+ /**
36
+ * Hashes the *unbound* SQL so one logical query keeps one identifier whatever its parameters are.
37
+ * Must agree with bigbrain-zth's `hashQueryShape`, or the same query buckets differently
38
+ * depending on which service ran it.
39
+ */
40
+ function hashQueryShape(rawSql: string): string {
41
+ return createHash('sha256').update(rawSql.replace(/\s+/g, ' ').trim()).digest('hex').slice(0, 16);
42
+ }
43
+
35
44
  /**
36
45
  * The permissions-aware pool returns different rows to different people, so the
37
46
  * cache key has to carry whatever decides that — the caller's roles and user
@@ -118,16 +127,18 @@ export async function runSnowflakeQuery(
118
127
  );
119
128
  }
120
129
 
121
- const queryHash = hashQuery(boundSql, params ?? {});
130
+ // Cache key stays parameter-sensitive; the pool identifier deliberately is not.
131
+ const queryCacheKey = hashQuery(boundSql, params ?? {});
132
+ const queryIdentifier = hashQueryShape(sql);
122
133
  const scope = cacheScope(useStateless);
123
- const cached = scope ? await readCache(queryHash, scope) : null;
134
+ const cached = scope ? await readCache(queryCacheKey, scope) : null;
124
135
  if (cached) {
125
136
  return cached;
126
137
  }
127
138
 
128
139
  const queryOptions = {
129
140
  query: boundSql,
130
- identifier: `z2h-query:${queryHash}`,
141
+ identifier: `z2h-query:${queryIdentifier}`,
131
142
  fallback: [] as SnowflakeRow[],
132
143
  timeoutInMs,
133
144
  convertToSingularResult: false,
@@ -157,7 +168,7 @@ export async function runSnowflakeQuery(
157
168
  }
158
169
  const rows = Array.isArray(data) ? data : [];
159
170
  if (scope) {
160
- await writeCache(queryHash, scope, rows);
171
+ await writeCache(queryCacheKey, scope, rows);
161
172
  }
162
173
  return rows;
163
174
  }
@@ -167,9 +178,10 @@ export async function runSnowflakeQuery(
167
178
  * correctness, so a failure here falls through to the warehouse rather than
168
179
  * failing the handler's query. Compressed, as bigbrain-zth stores the same rows.
169
180
  */
170
- async function readCache(queryHash: string, scope: string): Promise<SnowflakeRow[] | null> {
181
+ /** `queryHash` is pinned: it is in this pattern's `patternVariableKeys`, so it is Redis key material. */
182
+ async function readCache(queryCacheKey: string, scope: string): Promise<SnowflakeRow[] | null> {
171
183
  try {
172
- const hit = await getDefaultClient().getCompressed(CACHE_PATTERN, { queryHash, scope });
184
+ const hit = await getDefaultClient().getCompressed(CACHE_PATTERN, { queryHash: queryCacheKey, scope });
173
185
  return hit ? (JSON.parse(hit.toString()) as SnowflakeRow[]) : null;
174
186
  } catch (err) {
175
187
  logger.warn({ tag: 'z2h-snowflake', error: err instanceof Error ? err.message : String(err) }, 'cache read failed');
@@ -177,9 +189,9 @@ async function readCache(queryHash: string, scope: string): Promise<SnowflakeRow
177
189
  }
178
190
  }
179
191
 
180
- async function writeCache(queryHash: string, scope: string, rows: SnowflakeRow[]): Promise<void> {
192
+ async function writeCache(queryCacheKey: string, scope: string, rows: SnowflakeRow[]): Promise<void> {
181
193
  try {
182
- await getDefaultClient().setCompressed(CACHE_PATTERN, { queryHash, scope }, JSON.stringify(rows));
194
+ await getDefaultClient().setCompressed(CACHE_PATTERN, { queryHash: queryCacheKey, scope }, JSON.stringify(rows));
183
195
  } catch (err) {
184
196
  logger.warn(
185
197
  { tag: 'z2h-snowflake', error: err instanceof Error ? err.message : String(err) },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mondaydotcomorg/z2h-cli",
3
- "version": "0.22.0",
3
+ "version": "0.23.0",
4
4
  "bin": "./bin/z2h-cli.js",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -15,6 +15,16 @@
15
15
  "require": "./dist/constants.js",
16
16
  "types": "./dist/constants.d.ts"
17
17
  },
18
+ "./auth": {
19
+ "import": "./dist/esm/auth.mjs",
20
+ "require": "./dist/auth.js",
21
+ "types": "./dist/auth.d.ts"
22
+ },
23
+ "./s3": {
24
+ "import": "./dist/esm/s3.mjs",
25
+ "require": "./dist/s3.js",
26
+ "types": "./dist/s3.d.ts"
27
+ },
18
28
  "./package.json": "./package.json"
19
29
  },
20
30
  "nx": {
package/src/auth.ts ADDED
@@ -0,0 +1,2 @@
1
+ export { generateZ2HTokenCommand, type GenerateZ2HTokenOptions } from './commands/generate-z2h-token';
2
+ export { readZthAuth, Z2hAuthMissingError, Z2H_AUTH_FILE, type ZthAuth } from './util/auth/auth-store';
package/src/s3.ts ADDED
@@ -0,0 +1,2 @@
1
+ export { setupS3Client, getS3Client } from './util/s3/client';
2
+ export { uploadDir } from './util/s3/upload';
@@ -9,7 +9,7 @@
9
9
  },
10
10
  "dependencies": {
11
11
  "@mondaydotcomorg/trident-runtime": "^1.24.1",
12
- "@mondaydotcomorg/z2h-runtime-sdk": "^0.1.0",
12
+ "@mondaydotcomorg/z2h-runtime-sdk": "0.x",
13
13
  "@vibe/core": "^4.0.1",
14
14
  "react": "^18.2.0",
15
15
  "react-dom": "^18.2.0",
@@ -13,7 +13,11 @@ const FOREVER = 'public, immutable';
13
13
 
14
14
  const UPLOAD_CONCURRENCY = 5;
15
15
 
16
- export async function uploadDir(localDir: string, keyPrefix: string): Promise<string[]> {
16
+ export async function uploadDir(
17
+ localDir: string,
18
+ keyPrefix: string,
19
+ bucket: string = BUCKET_WRITE_NAME
20
+ ): Promise<string[]> {
17
21
  const entries = await readdir(localDir, { recursive: true, withFileTypes: true });
18
22
  const files = entries.filter(e => e.isFile()).map(e => path.relative(localDir, path.join(e.parentPath, e.name)));
19
23
 
@@ -27,7 +31,7 @@ export async function uploadDir(localDir: string, keyPrefix: string): Promise<st
27
31
  const key = `${keyPrefix}/${rel.split(path.sep).join('/')}`;
28
32
  await s3.send(
29
33
  new PutObjectCommand({
30
- Bucket: BUCKET_WRITE_NAME,
34
+ Bucket: bucket,
31
35
  Key: key,
32
36
  Body: body,
33
37
  ContentType: contentType,