@rex0220/kintone-sql-tools 3.8.0 → 3.9.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-cli/ksql.js CHANGED
@@ -7904,26 +7904,55 @@ var VALIDATION_META_COLUMNS = [
7904
7904
  "$err_row",
7905
7905
  "$err_field",
7906
7906
  "$err_code",
7907
- "$err_message"
7907
+ "$err_message",
7908
+ "$err_value",
7909
+ "$err_subtable",
7910
+ "$err_subrow",
7911
+ "$err_subrow_id"
7908
7912
  ];
7909
- function validateDmlCandidates(candidates, operation, payloadFields, targetFields, fieldInfos, statementNumber, numberPrecision, checkGroups = [], validateMissingCreateFields = true, includePreErrors = true) {
7913
+ function materializeDmlUpdateModeSparseRecords(candidates, targetFields, fieldInfos) {
7914
+ const infoByCode = new Map(fieldInfos.map((field) => [field.code, field]));
7915
+ for (const candidate of candidates) {
7916
+ if (candidate.mode !== "update") continue;
7917
+ candidate.record ??= {};
7918
+ for (const code of targetFields) {
7919
+ if (!candidate.payload.has(code)) continue;
7920
+ const original = candidate.payload.get(code);
7921
+ const type = infoByCode.get(code).fieldType;
7922
+ const preserveCodes = ["USER_SELECT", "ORGANIZATION_SELECT", "GROUP_SELECT"].includes(type) && Array.isArray(original) && original.every((item) => typeof item === "object" && item !== null && "code" in item);
7923
+ let normalized = original;
7924
+ try {
7925
+ normalized = normalizeRaw(original, type);
7926
+ } catch {
7927
+ }
7928
+ candidate.record[code] = { value: preserveCodes ? original : normalized };
7929
+ }
7930
+ }
7931
+ }
7932
+ function validateDmlCandidates(candidates, operation, payloadFields, targetFields, fieldInfos, statementNumber, numberPrecision, checkGroups = [], validateMissingCreateFields = true, includePreErrors = true, validationOptions = {}) {
7910
7933
  const infoByCode = new Map(fieldInfos.map((field) => [field.code, field]));
7911
7934
  const errors = [];
7912
7935
  const invalid = /* @__PURE__ */ new Set();
7936
+ const candidateResults = [];
7937
+ if (validationOptions.validateUpdateBuiltIns === false) {
7938
+ materializeDmlUpdateModeSparseRecords(candidates, targetFields, fieldInfos);
7939
+ }
7913
7940
  let firstEvaluationError;
7914
7941
  for (const candidate of candidates) {
7915
7942
  candidate.record ??= {};
7916
- const rowErrors = includePreErrors ? [...candidate.preErrors] : [];
7943
+ const preErrors = includePreErrors ? [...candidate.preErrors] : [];
7944
+ const builtInErrors = [];
7945
+ const checkErrors = [];
7946
+ const validateBuiltIns = candidate.mode === "create" || validationOptions.validateUpdateBuiltIns !== false;
7917
7947
  for (const code of targetFields) {
7918
7948
  if (!candidate.payload.has(code)) continue;
7919
- const result = validateAndNormalizeDmlValue(candidate.payload.get(code), infoByCode.get(code), numberPrecision);
7920
- if (!result.ok) rowErrors.push({ field: code, code: result.code, message: result.message });
7921
- else {
7922
- const original = candidate.payload.get(code);
7923
- const type = infoByCode.get(code).fieldType;
7924
- const preserveCodes = ["USER_SELECT", "ORGANIZATION_SELECT", "GROUP_SELECT"].includes(type) && Array.isArray(original) && original.every((item) => typeof item === "object" && item !== null && "code" in item);
7925
- candidate.record[code] = { value: preserveCodes ? original : result.value };
7926
- }
7949
+ const original = candidate.payload.get(code);
7950
+ const type = infoByCode.get(code).fieldType;
7951
+ const preserveCodes = ["USER_SELECT", "ORGANIZATION_SELECT", "GROUP_SELECT"].includes(type) && Array.isArray(original) && original.every((item) => typeof item === "object" && item !== null && "code" in item);
7952
+ if (!validateBuiltIns) continue;
7953
+ const result = validateAndNormalizeDmlValue(original, infoByCode.get(code), numberPrecision);
7954
+ if (!result.ok) builtInErrors.push({ field: code, code: result.code, message: result.message });
7955
+ else candidate.record[code] = { value: preserveCodes ? original : result.value };
7927
7956
  }
7928
7957
  if (validateMissingCreateFields && candidate.mode === "create") {
7929
7958
  for (const info of fieldInfos) {
@@ -7932,7 +7961,7 @@ function validateDmlCandidates(candidates, operation, payloadFields, targetField
7932
7961
  const emptyDefault = isEmptyDmlValue(info.defaultValue);
7933
7962
  if (!emptyDefault) {
7934
7963
  const defaultResult = validateAndNormalizeDmlValue(info.defaultValue, info, numberPrecision);
7935
- if (!defaultResult.ok) rowErrors.push({
7964
+ if (!defaultResult.ok) builtInErrors.push({
7936
7965
  field: info.code,
7937
7966
  code: defaultResult.code,
7938
7967
  message: `\u65E2\u5B9A\u5024: ${defaultResult.message}`
@@ -7940,9 +7969,9 @@ function validateDmlCandidates(candidates, operation, payloadFields, targetField
7940
7969
  } else {
7941
7970
  const emptyResult = validateAndNormalizeDmlValue("", info, numberPrecision);
7942
7971
  if (!emptyResult.ok) {
7943
- rowErrors.push({ field: info.code, code: emptyResult.code, message: emptyResult.message });
7972
+ builtInErrors.push({ field: info.code, code: emptyResult.code, message: emptyResult.message });
7944
7973
  } else if (info.required) {
7945
- rowErrors.push({ field: info.code, code: "ERR_REQUIRED", message: `${info.code} \u306F\u5FC5\u9808\u3067\u3059` });
7974
+ builtInErrors.push({ field: info.code, code: "ERR_REQUIRED", message: `${info.code} \u306F\u5FC5\u9808\u3067\u3059` });
7946
7975
  }
7947
7976
  }
7948
7977
  }
@@ -7958,14 +7987,13 @@ function validateDmlCandidates(candidates, operation, payloadFields, targetField
7958
7987
  };
7959
7988
  try {
7960
7989
  for (const custom of evaluateCustomChecks(checkGroups, row, resolveType)) {
7961
- rowErrors.push({ field: "", code: "ERR_CHECK", message: custom.message });
7990
+ checkErrors.push({ field: "", code: "ERR_CHECK", message: custom.message });
7962
7991
  }
7963
7992
  } catch (error) {
7964
7993
  firstEvaluationError ??= error;
7965
7994
  }
7966
7995
  }
7967
- if (rowErrors.length > 0) invalid.add(candidate.rowNumber);
7968
- for (const error of rowErrors) {
7996
+ const materializeErrors = (source) => source.map((error) => {
7969
7997
  const row = {};
7970
7998
  for (const field of payloadFields) row[field] = renderValidationValue(candidate.payload.get(field));
7971
7999
  row["$err_statement"] = String(statementNumber);
@@ -7974,11 +8002,25 @@ function validateDmlCandidates(candidates, operation, payloadFields, targetField
7974
8002
  row["$err_field"] = error.field;
7975
8003
  row["$err_code"] = error.code;
7976
8004
  row["$err_message"] = error.message;
7977
- errors.push(row);
7978
- }
8005
+ row["$err_value"] = "";
8006
+ row["$err_subtable"] = "";
8007
+ row["$err_subrow"] = "";
8008
+ row["$err_subrow_id"] = "";
8009
+ return row;
8010
+ });
8011
+ const materialized = {
8012
+ rowNumber: candidate.rowNumber,
8013
+ preErrors: materializeErrors(preErrors),
8014
+ builtInErrors: materializeErrors(builtInErrors),
8015
+ checkErrors: materializeErrors(checkErrors)
8016
+ };
8017
+ candidateResults.push(materialized);
8018
+ const rowErrors = [...materialized.preErrors, ...materialized.builtInErrors, ...materialized.checkErrors];
8019
+ if (rowErrors.length > 0) invalid.add(candidate.rowNumber);
8020
+ errors.push(...rowErrors);
7979
8021
  }
7980
8022
  if (firstEvaluationError !== void 0) throw firstEvaluationError;
7981
- return { errors, invalidRows: invalid.size, invalidRowNumbers: invalid };
8023
+ return { errors, invalidRows: invalid.size, invalidRowNumbers: invalid, candidateResults };
7982
8024
  }
7983
8025
  function renderValidationValue(value) {
7984
8026
  if (value == null) return "";
@@ -8085,13 +8127,7 @@ var NON_AUDIT_SYSTEM_TYPES = /* @__PURE__ */ new Set([
8085
8127
  "CATEGORY",
8086
8128
  "REFERENCE_TABLE"
8087
8129
  ]);
8088
- var POST_IMAGE_VALIDATION_SUFFIX_COLUMNS = [
8089
- ...VALIDATION_META_COLUMNS,
8090
- "$err_value",
8091
- "$err_subtable",
8092
- "$err_subrow",
8093
- "$err_subrow_id"
8094
- ];
8130
+ var POST_IMAGE_VALIDATION_SUFFIX_COLUMNS = VALIDATION_META_COLUMNS;
8095
8131
  function buildPostImageFieldIndex(fieldInfos, payloadFields = ["$id"]) {
8096
8132
  const metadata = buildValidationFieldMetadataIndex(fieldInfos);
8097
8133
  const topLevel = metadata.topLevel.filter((field) => field.fieldType !== "SUBTABLE" && field.fieldType !== "FILE" && !NON_AUDIT_SYSTEM_TYPES.has(field.fieldType));
@@ -10299,6 +10335,71 @@ function toFlatString(value) {
10299
10335
  }
10300
10336
  }
10301
10337
 
10338
+ // src/core/dmlPrevalidation.ts
10339
+ function collectDmlPrevalidationSnapshotFields(fieldIndex) {
10340
+ return [
10341
+ "$id",
10342
+ .../* @__PURE__ */ new Set([
10343
+ ...fieldIndex.topLevel.map((field) => field.code).filter((code) => code !== "$id" && code !== "$revision"),
10344
+ ...fieldIndex.subtables.keys()
10345
+ ])
10346
+ ];
10347
+ }
10348
+ function buildDmlValidationPostImage(snapshot, sparseRecord) {
10349
+ const postImage = deepClone(snapshot);
10350
+ for (const [field, cell] of Object.entries(sparseRecord)) {
10351
+ postImage[field] = deepClone(cell);
10352
+ }
10353
+ return postImage;
10354
+ }
10355
+ function mergeDmlCandidateValidation(input) {
10356
+ const errors = [
10357
+ ...input.preErrors.map((row) => normalizePlainError(row)),
10358
+ ...input.postImageErrors.map((row) => normalizePlainError(row, row["$err_subtable"] !== "")),
10359
+ ...input.checkErrors.map((row) => normalizePlainError(row))
10360
+ ];
10361
+ const invalidRowNumbers = /* @__PURE__ */ new Set();
10362
+ if (errors.length > 0) invalidRowNumbers.add(input.rowNumber);
10363
+ const writeRecord = {};
10364
+ for (const field of new Set(input.setFields)) {
10365
+ if (!Object.prototype.hasOwnProperty.call(input.normalizedPostImage, field)) {
10366
+ throw new Error(`InternalError: normalized post-image is missing SET field: ${field}`);
10367
+ }
10368
+ writeRecord[field] = deepClone(input.normalizedPostImage[field]);
10369
+ }
10370
+ return {
10371
+ errors,
10372
+ invalidRows: invalidRowNumbers.size,
10373
+ invalidRowNumbers,
10374
+ writeRecord
10375
+ };
10376
+ }
10377
+ function normalizePlainError(row, childCell = false) {
10378
+ return {
10379
+ ...row,
10380
+ $err_value: childCell ? row["$err_value"] ?? "" : "",
10381
+ $err_subtable: childCell ? row["$err_subtable"] ?? "" : "",
10382
+ $err_subrow: childCell ? row["$err_subrow"] ?? "" : "",
10383
+ $err_subrow_id: childCell ? row["$err_subrow_id"] ?? "" : ""
10384
+ };
10385
+ }
10386
+ function deepClone(value, seen = /* @__PURE__ */ new Map()) {
10387
+ if (value === null || typeof value !== "object") return value;
10388
+ const object = value;
10389
+ const existing = seen.get(object);
10390
+ if (existing !== void 0) return existing;
10391
+ if (Array.isArray(value)) {
10392
+ const clone2 = [];
10393
+ seen.set(object, clone2);
10394
+ for (const item of value) clone2.push(deepClone(item, seen));
10395
+ return clone2;
10396
+ }
10397
+ const clone = {};
10398
+ seen.set(object, clone);
10399
+ for (const [key, child] of Object.entries(value)) clone[key] = deepClone(child, seen);
10400
+ return clone;
10401
+ }
10402
+
10302
10403
  // src/core/optimization/whereCapability.ts
10303
10404
  var RANGE_AND_EQUALITY = ["=", "!=", ">", "<", ">=", "<="];
10304
10405
  var EQUALITY_IN = ["=", "!=", "in", "not in"];
@@ -14501,15 +14602,72 @@ async function prepareDmlValidation(stmt, client, options, cacheContext, tempTab
14501
14602
  await assertDmlWhereCapability(stmt, client, cacheContext);
14502
14603
  }
14503
14604
  const infoByCode = new Map(fieldInfos.map((field) => [field.code, field]));
14504
- const numberPrecision = await loadNumberPrecisionForTargets(
14605
+ let numberPrecision = await loadNumberPrecisionForTargets(
14505
14606
  stmt.appId,
14506
14607
  targetFields,
14507
14608
  fieldInfos,
14508
14609
  client,
14509
14610
  cacheContext
14510
14611
  );
14511
- const candidates = await materializeValidationCandidates(stmt, operation, client, options, cacheContext, tempTables, infoByCode);
14512
- const { errors, invalidRows, invalidRowNumbers } = validateDmlCandidates(
14612
+ const fieldIndex = buildPostImageFieldIndex(fieldInfos, payloadFields);
14613
+ const snapshotFields = collectDmlPrevalidationSnapshotFields(fieldIndex);
14614
+ const candidates = (await materializeValidationCandidates(
14615
+ stmt,
14616
+ operation,
14617
+ client,
14618
+ options,
14619
+ cacheContext,
14620
+ tempTables,
14621
+ infoByCode,
14622
+ stmt.type === "UPDATE" ? snapshotFields : void 0
14623
+ )).sort((left, right) => left.rowNumber - right.rowNumber);
14624
+ const updateCandidates = candidates.filter((candidate) => candidate.mode === "update");
14625
+ const productionUpdateLoader = stmt.type === "UPDATE" ? loadMaterializedUpdateSnapshots : stmt.type.startsWith("UPSERT") ? (input) => loadUpsertValidationSnapshots(
14626
+ input,
14627
+ client,
14628
+ options.maxRecords ?? 1e4
14629
+ ) : void 0;
14630
+ const updateSnapshotLoader = options.loadUpdateModeSnapshots ?? productionUpdateLoader;
14631
+ const usePreparedPostImages = updateCandidates.length > 0 && updateSnapshotLoader !== void 0;
14632
+ const preparedPostImages = /* @__PURE__ */ new Map();
14633
+ if (usePreparedPostImages) {
14634
+ materializeDmlUpdateModeSparseRecords(updateCandidates, targetFields, fieldInfos);
14635
+ const snapshots = await updateSnapshotLoader({
14636
+ appId: stmt.appId,
14637
+ candidates: updateCandidates,
14638
+ fields: snapshotFields
14639
+ });
14640
+ const postImages = /* @__PURE__ */ new Map();
14641
+ for (const candidate of updateCandidates) {
14642
+ if (candidate.targetId === void 0) {
14643
+ throw new Error(`InternalError: update-mode validation candidate has no targetId (row=${candidate.rowNumber}).`);
14644
+ }
14645
+ const snapshot = snapshots.get(candidate.targetId);
14646
+ if (!snapshot) {
14647
+ throw new Error(`InternalError: update-mode snapshot is missing for record ${candidate.targetId}.`);
14648
+ }
14649
+ const postImage = buildDmlValidationPostImage(snapshot, candidate.record ?? {});
14650
+ postImages.set(candidate.rowNumber, postImage);
14651
+ }
14652
+ if (numberPrecision === void 0 && [...postImages.values()].some(
14653
+ (record) => postImageNeedsNumberPrecision(record, fieldIndex)
14654
+ )) {
14655
+ numberPrecision = await getNumberPrecisionCached(stmt.appId, client, cacheContext);
14656
+ }
14657
+ for (const candidate of updateCandidates) {
14658
+ const postImage = postImages.get(candidate.rowNumber);
14659
+ if (!postImage) throw new Error(`InternalError: validation post-image is missing for row ${candidate.rowNumber}.`);
14660
+ preparedPostImages.set(candidate.rowNumber, validatePostImage(
14661
+ postImage,
14662
+ fieldIndex,
14663
+ numberPrecision,
14664
+ statementNumber,
14665
+ candidate.rowNumber,
14666
+ operation
14667
+ ));
14668
+ }
14669
+ }
14670
+ const candidateValidation = validateDmlCandidates(
14513
14671
  candidates,
14514
14672
  operation,
14515
14673
  payloadFields,
@@ -14519,8 +14677,41 @@ async function prepareDmlValidation(stmt, client, options, cacheContext, tempTab
14519
14677
  numberPrecision,
14520
14678
  stmt.checkGroups ?? [],
14521
14679
  validateMissingCreateFields,
14522
- includePreErrors
14680
+ includePreErrors,
14681
+ { validateUpdateBuiltIns: !usePreparedPostImages }
14523
14682
  );
14683
+ let { errors, invalidRows, invalidRowNumbers } = candidateValidation;
14684
+ if (usePreparedPostImages) {
14685
+ const detailsByRow = new Map(candidateValidation.candidateResults.map((detail) => [detail.rowNumber, detail]));
14686
+ errors = [];
14687
+ invalidRowNumbers = /* @__PURE__ */ new Set();
14688
+ for (const candidate of candidates) {
14689
+ const detail = detailsByRow.get(candidate.rowNumber);
14690
+ if (!detail) throw new Error(`InternalError: validation detail is missing for row ${candidate.rowNumber}.`);
14691
+ if (candidate.mode === "create") {
14692
+ const candidateErrors = [...detail.preErrors, ...detail.builtInErrors, ...detail.checkErrors];
14693
+ errors.push(...candidateErrors);
14694
+ if (candidateErrors.length > 0) invalidRowNumbers.add(candidate.rowNumber);
14695
+ continue;
14696
+ }
14697
+ const postImageValidation = preparedPostImages.get(candidate.rowNumber);
14698
+ if (!postImageValidation) {
14699
+ throw new Error(`InternalError: prepared post-image validation is missing for row ${candidate.rowNumber}.`);
14700
+ }
14701
+ const merged = mergeDmlCandidateValidation({
14702
+ rowNumber: candidate.rowNumber,
14703
+ setFields: targetFields,
14704
+ normalizedPostImage: postImageValidation.normalizedRecord,
14705
+ preErrors: detail.preErrors,
14706
+ postImageErrors: postImageValidation.errors,
14707
+ checkErrors: detail.checkErrors
14708
+ });
14709
+ candidate.record = merged.writeRecord;
14710
+ errors.push(...merged.errors);
14711
+ for (const rowNumber of merged.invalidRowNumbers) invalidRowNumbers.add(rowNumber);
14712
+ }
14713
+ invalidRows = invalidRowNumbers.size;
14714
+ }
14524
14715
  const columns = [...payloadFields, ...VALIDATION_META_COLUMNS];
14525
14716
  const result = {
14526
14717
  type: "VALIDATION",
@@ -14546,12 +14737,10 @@ async function prepareDmlValidation(stmt, client, options, cacheContext, tempTab
14546
14737
  const info = infoByCode.get(column);
14547
14738
  if (info) columnMeta.set(column, materializedMetaFromFieldInfo(info, stmt.appId));
14548
14739
  }
14549
- columnMeta.set("$err_statement", syntheticColumnMeta("number"));
14550
- columnMeta.set("$err_operation", syntheticColumnMeta("string"));
14551
- columnMeta.set("$err_row", syntheticColumnMeta("number"));
14552
- columnMeta.set("$err_field", syntheticColumnMeta("string"));
14553
- columnMeta.set("$err_code", syntheticColumnMeta("string"));
14554
- columnMeta.set("$err_message", syntheticColumnMeta("string"));
14740
+ const numericValidationMeta = /* @__PURE__ */ new Set(["$err_statement", "$err_row"]);
14741
+ for (const column of VALIDATION_META_COLUMNS) {
14742
+ columnMeta.set(column, syntheticColumnMeta(numericValidationMeta.has(column) ? "number" : "string"));
14743
+ }
14555
14744
  materializedMetaByValidationResult.set(result, columnMeta);
14556
14745
  return { result, candidates, invalidRowNumbers, columnMeta };
14557
14746
  }
@@ -14626,8 +14815,17 @@ async function executeOnErrorSkip(stmt, client, options, cacheContext, tempTable
14626
14815
  }
14627
14816
  return { type: "UPSERT", insertedCount, updatedCount: updates.length, ...common };
14628
14817
  }
14629
- async function materializeValidationCandidates(stmt, operation, client, options, cacheContext, tempTables, infoByCode) {
14630
- if (stmt.type === "UPDATE") return materializeUpdateValidationCandidates(stmt, client, options, cacheContext, tempTables);
14818
+ async function materializeValidationCandidates(stmt, operation, client, options, cacheContext, tempTables, infoByCode, updateSnapshotFields) {
14819
+ if (stmt.type === "UPDATE") {
14820
+ return materializeUpdateValidationCandidates(
14821
+ stmt,
14822
+ client,
14823
+ options,
14824
+ cacheContext,
14825
+ tempTables,
14826
+ updateSnapshotFields
14827
+ );
14828
+ }
14631
14829
  let rows;
14632
14830
  let sourceRows;
14633
14831
  let sourcePresence;
@@ -14740,40 +14938,70 @@ function assertCheckComparisonTypes(stmt, types) {
14740
14938
  }
14741
14939
  }
14742
14940
  }
14743
- async function materializeUpdateValidationCandidates(stmt, client, options, cacheContext, tempTables) {
14744
- if (stmt.from) return materializeUpdateFromValidationCandidates(stmt, stmt.from, client, options, cacheContext, tempTables);
14941
+ async function materializeUpdateValidationCandidates(stmt, client, options, cacheContext, tempTables, snapshotFields) {
14942
+ if (stmt.from) {
14943
+ return materializeUpdateFromValidationCandidates(
14944
+ stmt,
14945
+ stmt.from,
14946
+ client,
14947
+ options,
14948
+ cacheContext,
14949
+ tempTables,
14950
+ snapshotFields
14951
+ );
14952
+ }
14745
14953
  await resolveSetSubqueries(stmt.assignments, client, options, cacheContext);
14746
14954
  const fieldTypes = await getFieldTypeMap(stmt.appId, client, cacheContext);
14747
14955
  const checkTargetFields = assertUpdateCheckRefs(stmt, fieldTypes);
14748
14956
  assertCheckComparisonTypes(stmt, updateEvaluationTypes(fieldTypes, stmt.appId));
14749
14957
  let records;
14750
14958
  let evaluationById = /* @__PURE__ */ new Map();
14959
+ let snapshotsById = /* @__PURE__ */ new Map();
14751
14960
  if (hasRowDependentAssignment(stmt)) {
14752
14961
  const getParams = updateToGetQueryForArith(stmt);
14753
- const fields = [.../* @__PURE__ */ new Set([...getParams.fields, ...checkTargetFields])];
14962
+ const fields = [.../* @__PURE__ */ new Set([...getParams.fields, ...checkTargetFields, ...snapshotFields ?? []])];
14754
14963
  const resolved = await fetchRecordsForSharedPlan(client.getRecords, getParams.app, getParams.query, fields, {
14755
14964
  maxRecords: options.maxRecords ?? 1e4,
14756
14965
  parallel: options.fetchParallel ?? 1,
14757
14966
  onLimit: "error"
14758
14967
  });
14759
- evaluationById = new Map(resolved.records.map((record) => [Number(record["$id"]?.value), record]));
14968
+ snapshotsById = indexDmlUpdateSnapshots(resolved.records);
14969
+ evaluationById = snapshotsById;
14760
14970
  records = updateToPutBatchesArith(stmt, resolved.records, fieldTypes).flatMap((batch) => batch.records);
14761
14971
  } else {
14762
14972
  const getParams = updateToGetQuery(stmt);
14763
14973
  if (checkTargetFields.length > 0) {
14764
- const resolved = await fetchRecordsForSharedPlan(client.getRecords, getParams.app, getParams.query, [.../* @__PURE__ */ new Set(["$id", ...checkTargetFields])], {
14974
+ const fields = [.../* @__PURE__ */ new Set(["$id", ...checkTargetFields, ...snapshotFields ?? []])];
14975
+ const resolved = await fetchRecordsForSharedPlan(client.getRecords, getParams.app, getParams.query, fields, {
14765
14976
  maxRecords: options.maxRecords ?? 1e4,
14766
14977
  parallel: options.fetchParallel ?? 1,
14767
14978
  onLimit: "error"
14768
14979
  });
14769
- evaluationById = new Map(resolved.records.map((record) => [Number(record["$id"]?.value), record]));
14980
+ snapshotsById = indexDmlUpdateSnapshots(resolved.records);
14981
+ evaluationById = snapshotsById;
14770
14982
  records = updateToPutBatches(stmt, [...evaluationById.keys()], fieldTypes).flatMap((batch) => batch.records);
14771
14983
  } else {
14772
- const resolved = await resolveDmlTargetIds(client.getRecords, getParams.app, getParams.query, {
14773
- maxRecords: options.maxRecords ?? 1e4,
14774
- parallel: options.fetchParallel ?? 1
14775
- });
14776
- records = updateToPutBatches(stmt, resolved.ids, fieldTypes).flatMap((batch) => batch.records);
14984
+ if (snapshotFields) {
14985
+ const resolved = await fetchRecordsForSharedPlan(
14986
+ client.getRecords,
14987
+ getParams.app,
14988
+ getParams.query,
14989
+ [...snapshotFields],
14990
+ {
14991
+ maxRecords: options.maxRecords ?? 1e4,
14992
+ parallel: options.fetchParallel ?? 1,
14993
+ onLimit: "error"
14994
+ }
14995
+ );
14996
+ snapshotsById = indexDmlUpdateSnapshots(resolved.records);
14997
+ records = updateToPutBatches(stmt, [...snapshotsById.keys()], fieldTypes).flatMap((batch) => batch.records);
14998
+ } else {
14999
+ const resolved = await resolveDmlTargetIds(client.getRecords, getParams.app, getParams.query, {
15000
+ maxRecords: options.maxRecords ?? 1e4,
15001
+ parallel: options.fetchParallel ?? 1
15002
+ });
15003
+ records = updateToPutBatches(stmt, resolved.ids, fieldTypes).flatMap((batch) => batch.records);
15004
+ }
14777
15005
  }
14778
15006
  }
14779
15007
  return records.sort((a, b) => a.id - b.id).map((entry, index) => ({
@@ -14784,10 +15012,86 @@ async function materializeUpdateValidationCandidates(stmt, client, options, cach
14784
15012
  preErrors: [],
14785
15013
  record: entry.record,
14786
15014
  targetId: entry.id,
15015
+ validationSnapshot: snapshotsById.get(entry.id),
14787
15016
  evaluationRow: updateEvaluationRow(evaluationById.get(entry.id), stmt.appId),
14788
15017
  evaluationFieldTypes: updateEvaluationTypes(fieldTypes, stmt.appId)
14789
15018
  }));
14790
15019
  }
15020
+ function indexDmlUpdateSnapshots(records) {
15021
+ const snapshots = /* @__PURE__ */ new Map();
15022
+ for (const record of records) {
15023
+ const rawId = record["$id"]?.value;
15024
+ const id = Number(rawId);
15025
+ if (!Number.isSafeInteger(id) || id <= 0) {
15026
+ throw new Error(`InternalError: invalid $id in UPDATE validation snapshot: ${String(rawId)}.`);
15027
+ }
15028
+ if (snapshots.has(id)) {
15029
+ throw new Error(`InternalError: duplicate $id in UPDATE validation snapshot: ${id}.`);
15030
+ }
15031
+ snapshots.set(id, record);
15032
+ }
15033
+ return snapshots;
15034
+ }
15035
+ async function loadMaterializedUpdateSnapshots(input) {
15036
+ const snapshots = /* @__PURE__ */ new Map();
15037
+ for (const candidate of input.candidates) {
15038
+ if (candidate.targetId === void 0 || !candidate.validationSnapshot) {
15039
+ throw new Error(
15040
+ `InternalError: update-mode snapshot is missing for record ${String(candidate.targetId)}.`
15041
+ );
15042
+ }
15043
+ if (snapshots.has(candidate.targetId)) {
15044
+ throw new Error(`InternalError: duplicate UPDATE validation candidate target: ${candidate.targetId}.`);
15045
+ }
15046
+ snapshots.set(candidate.targetId, candidate.validationSnapshot);
15047
+ }
15048
+ return snapshots;
15049
+ }
15050
+ async function loadUpsertValidationSnapshots(input, client, maxRecords) {
15051
+ const updateIds = [...new Set(input.candidates.map((candidate) => {
15052
+ const id = candidate.targetId;
15053
+ if (!Number.isSafeInteger(id) || id === void 0 || id <= 0) {
15054
+ throw new Error(
15055
+ `InternalError: invalid targetId in UPSERT validation candidate: ${String(id)}.`
15056
+ );
15057
+ }
15058
+ return id;
15059
+ }))];
15060
+ if (updateIds.length > maxRecords) {
15061
+ throw new FetchAllLimitError(
15062
+ `\u53D6\u5F97\u4EF6\u6570\u304C\u4E0A\u9650\uFF08${maxRecords} \u4EF6\uFF09\u3092\u8D85\u3048\u307E\u3057\u305F\u3002WHERE \u53E5\u3067\u7D5E\u308A\u8FBC\u3080\u304B\u3001maxRecords \u3092\u5F15\u304D\u4E0A\u3052\u3066\u304F\u3060\u3055\u3044\u3002`
15063
+ );
15064
+ }
15065
+ const requestedIds = new Set(updateIds);
15066
+ const snapshots = /* @__PURE__ */ new Map();
15067
+ for (const ids of splitChunks(updateIds, 100)) {
15068
+ const response = await client.getRecords({
15069
+ app: input.appId,
15070
+ query: `$id in (${ids.join(",")}) limit 500`,
15071
+ fields: [...new Set(input.fields)]
15072
+ });
15073
+ for (const snapshot of response.records) {
15074
+ const rawId = snapshot["$id"]?.value;
15075
+ const id = Number(rawId);
15076
+ if (!Number.isSafeInteger(id) || id <= 0) {
15077
+ throw new Error(`InternalError: invalid $id in UPSERT validation snapshot: ${String(rawId)}.`);
15078
+ }
15079
+ if (!requestedIds.has(id)) {
15080
+ throw new Error(`InternalError: unexpected $id in UPSERT validation snapshot: ${id}.`);
15081
+ }
15082
+ if (snapshots.has(id)) {
15083
+ throw new Error(`InternalError: duplicate $id in UPSERT validation snapshot: ${id}.`);
15084
+ }
15085
+ snapshots.set(id, snapshot);
15086
+ }
15087
+ }
15088
+ for (const id of updateIds) {
15089
+ if (!snapshots.has(id)) {
15090
+ throw new Error(`InternalError: update-mode snapshot is missing for record ${id}.`);
15091
+ }
15092
+ }
15093
+ return snapshots;
15094
+ }
14791
15095
  function assertUpdateCheckRefs(stmt, targetTypes) {
14792
15096
  if (stmt.from) return [];
14793
15097
  const fields = /* @__PURE__ */ new Set();
@@ -14818,13 +15122,22 @@ function updateEvaluationTypes(types, appId) {
14818
15122
  [`APP${appId}.$id`, "RECORD_NUMBER"]
14819
15123
  ]);
14820
15124
  }
14821
- async function materializeUpdateFromValidationCandidates(stmt, from, client, options, cacheContext, tempTables) {
15125
+ async function materializeUpdateFromValidationCandidates(stmt, from, client, options, cacheContext, tempTables, snapshotFields) {
14822
15126
  const scope = await resolveUpdateFromCheckScope(stmt, from, client, cacheContext, tempTables);
14823
15127
  assertCheckComparisonTypes(stmt, scope.evaluationTypes);
14824
- const matched = await resolveUpdateFromMatchedRecords(stmt, from, client, options, cacheContext, tempTables);
15128
+ const matched = await resolveUpdateFromMatchedRecords(
15129
+ stmt,
15130
+ from,
15131
+ client,
15132
+ options,
15133
+ cacheContext,
15134
+ tempTables,
15135
+ snapshotFields
15136
+ );
14825
15137
  const fieldTypes = await getFieldTypeMap(stmt.appId, client, cacheContext);
14826
15138
  const records = updateFromToPutBatches(stmt, matched, fieldTypes).flatMap((batch) => batch.records);
14827
15139
  const matchedById = new Map(matched.map((pair) => [Number(pair.target["$id"]?.value), pair]));
15140
+ const snapshotsById = snapshotFields ? indexDmlUpdateSnapshots(matched.map((pair) => pair.target)) : /* @__PURE__ */ new Map();
14828
15141
  return records.sort((a, b) => a.id - b.id).map((entry, index) => ({
14829
15142
  rowNumber: index + 1,
14830
15143
  operation: "UPDATE",
@@ -14833,6 +15146,7 @@ async function materializeUpdateFromValidationCandidates(stmt, from, client, opt
14833
15146
  preErrors: [],
14834
15147
  record: entry.record,
14835
15148
  targetId: entry.id,
15149
+ validationSnapshot: snapshotsById.get(entry.id),
14836
15150
  evaluationRow: updateFromEvaluationRow(matchedById.get(entry.id), stmt.appId, from.alias),
14837
15151
  evaluationFieldTypes: scope.evaluationTypes
14838
15152
  }));
@@ -14846,7 +15160,7 @@ var UPDATE_FROM_UNSUPPORTED_SOURCE_TYPES = /* @__PURE__ */ new Set([
14846
15160
  "GROUP_SELECT",
14847
15161
  "FILE"
14848
15162
  ]);
14849
- async function resolveUpdateFromMatchedRecords(stmt, from, client, options, cacheContext, tempTables) {
15163
+ async function resolveUpdateFromMatchedRecords(stmt, from, client, options, cacheContext, tempTables, snapshotFields) {
14850
15164
  const joinKind = await resolveUpdateFromTargetJoinKind(stmt, from, client, cacheContext);
14851
15165
  const checkScope = await resolveUpdateFromCheckScope(stmt, from, client, cacheContext, tempTables);
14852
15166
  const sourceFields = [...new Set(stmt.assignments.filter((a) => a.value.type === "SOURCE_FIELD").map((a) => a.value.type === "SOURCE_FIELD" ? a.value.field : "").concat(checkScope.sourceFields))];
@@ -14875,7 +15189,11 @@ async function resolveUpdateFromMatchedRecords(stmt, from, client, options, cach
14875
15189
  }
14876
15190
  if (sourceByKey.size === 0) return [];
14877
15191
  const maxRecords = options.maxRecords ?? 1e4;
14878
- const targetFields = [.../* @__PURE__ */ new Set([...collectUpdateFromTargetFields(stmt), ...checkScope.targetFields])];
15192
+ const targetFields = [.../* @__PURE__ */ new Set([
15193
+ ...collectUpdateFromTargetFields(stmt),
15194
+ ...checkScope.targetFields,
15195
+ ...snapshotFields ?? []
15196
+ ])];
14879
15197
  const filterQuery = from.targetFilter === null ? "" : updateToGetQuery({ ...stmt, from: null, where: from.targetFilter, checkGroups: void 0 }).query;
14880
15198
  const targetRecords = [];
14881
15199
  const seenTargetIds = /* @__PURE__ */ new Set();
@@ -18484,6 +18802,189 @@ function getCursorLeaseManager(host, maxActive = DEFAULT_MAX_ACTIVE) {
18484
18802
  return manager;
18485
18803
  }
18486
18804
 
18805
+ // src/node/kintoneMetadata.ts
18806
+ var KINTONE_METADATA_RESOURCES = [
18807
+ "app",
18808
+ "fields",
18809
+ "layout",
18810
+ "settings",
18811
+ "status",
18812
+ "views",
18813
+ "reports",
18814
+ "customize"
18815
+ ];
18816
+ var KINTONE_METADATA_LANGS = ["default", "user", "ja", "en", "zh"];
18817
+ var KINTONE_METADATA_MAX_RESPONSE_BYTES = 2097152;
18818
+ var ResponseTooLargeError = class extends Error {
18819
+ constructor(maxBytes = KINTONE_METADATA_MAX_RESPONSE_BYTES, responseBytes) {
18820
+ super(`ResponseTooLargeError: kintone metadata response exceeds ${maxBytes} bytes.`);
18821
+ this.maxBytes = maxBytes;
18822
+ this.responseBytes = responseBytes;
18823
+ this.name = "ResponseTooLargeError";
18824
+ }
18825
+ };
18826
+ var InvalidJsonResponseError = class extends Error {
18827
+ constructor(cause) {
18828
+ super("InvalidJsonResponseError: kintone metadata response is not valid JSON.");
18829
+ this.name = "InvalidJsonResponseError";
18830
+ this.cause = cause;
18831
+ }
18832
+ };
18833
+ var ArgumentError = class extends Error {
18834
+ constructor(message) {
18835
+ super(`ArgumentError: ${message}`);
18836
+ this.name = "ArgumentError";
18837
+ }
18838
+ };
18839
+ var CapabilityError = class extends Error {
18840
+ constructor(message) {
18841
+ super(`CapabilityError: ${message}`);
18842
+ this.name = "CapabilityError";
18843
+ }
18844
+ };
18845
+ var RESOURCE_DEFINITIONS = {
18846
+ app: {
18847
+ productionPath: "/app.json",
18848
+ appParameter: "id",
18849
+ allowsLang: false,
18850
+ authCapability: "token|userpass"
18851
+ },
18852
+ fields: {
18853
+ productionPath: "/app/form/fields.json",
18854
+ previewPath: "/preview/app/form/fields.json",
18855
+ appParameter: "app",
18856
+ allowsLang: true,
18857
+ authCapability: "token|userpass"
18858
+ },
18859
+ layout: {
18860
+ productionPath: "/app/form/layout.json",
18861
+ previewPath: "/preview/app/form/layout.json",
18862
+ appParameter: "app",
18863
+ allowsLang: false,
18864
+ authCapability: "token|userpass"
18865
+ },
18866
+ settings: {
18867
+ productionPath: "/app/settings.json",
18868
+ previewPath: "/preview/app/settings.json",
18869
+ appParameter: "app",
18870
+ allowsLang: true,
18871
+ authCapability: "token|userpass"
18872
+ },
18873
+ status: {
18874
+ productionPath: "/app/status.json",
18875
+ previewPath: "/preview/app/status.json",
18876
+ appParameter: "app",
18877
+ allowsLang: true,
18878
+ authCapability: "token|userpass"
18879
+ },
18880
+ views: {
18881
+ productionPath: "/app/views.json",
18882
+ previewPath: "/preview/app/views.json",
18883
+ appParameter: "app",
18884
+ allowsLang: true,
18885
+ authCapability: "token|userpass"
18886
+ },
18887
+ reports: {
18888
+ productionPath: "/app/reports.json",
18889
+ previewPath: "/preview/app/reports.json",
18890
+ appParameter: "app",
18891
+ allowsLang: true,
18892
+ authCapability: "token|userpass"
18893
+ },
18894
+ customize: {
18895
+ productionPath: "/app/customize.json",
18896
+ previewPath: "/preview/app/customize.json",
18897
+ appParameter: "app",
18898
+ allowsLang: false,
18899
+ authCapability: "userpass-only"
18900
+ }
18901
+ };
18902
+ var RESOURCE_SET = new Set(KINTONE_METADATA_RESOURCES);
18903
+ var LANG_SET = new Set(KINTONE_METADATA_LANGS);
18904
+ var API_BASE_PATH_PATTERN = /^\/k\/(?:guest\/([1-9]\d*)\/)?v1$/;
18905
+ function assertResolvedAppId(resolvedAppId) {
18906
+ if (!Number.isSafeInteger(resolvedAppId) || resolvedAppId <= 0) {
18907
+ throw new ArgumentError("resolved app ID must be a positive safe integer.");
18908
+ }
18909
+ }
18910
+ function assertApiBasePath(apiBasePath) {
18911
+ const match = API_BASE_PATH_PATTERN.exec(apiBasePath);
18912
+ if (!match) {
18913
+ throw new ArgumentError("apiBasePath must be /k/v1 or /k/guest/<positive safe integer>/v1.");
18914
+ }
18915
+ if (match[1] !== void 0) {
18916
+ const guestSpaceId = Number(match[1]);
18917
+ if (!Number.isSafeInteger(guestSpaceId) || guestSpaceId <= 0) {
18918
+ throw new ArgumentError("apiBasePath guest space ID must be a positive safe integer.");
18919
+ }
18920
+ }
18921
+ }
18922
+ function validateRequest(request) {
18923
+ if (typeof request !== "object" || request === null || Array.isArray(request)) {
18924
+ throw new ArgumentError("metadata request must be an object.");
18925
+ }
18926
+ const candidate = request;
18927
+ const resource = candidate.resource;
18928
+ if (typeof resource !== "string" || !RESOURCE_SET.has(resource)) {
18929
+ throw new ArgumentError(`unsupported metadata resource: ${String(resource)}.`);
18930
+ }
18931
+ const typedResource = resource;
18932
+ const definition = RESOURCE_DEFINITIONS[typedResource];
18933
+ const allowedKeys = definition.allowsLang ? /* @__PURE__ */ new Set(["resource", "preview", "lang"]) : /* @__PURE__ */ new Set(["resource", "preview"]);
18934
+ const unexpectedKey = Object.keys(candidate).find((key) => !allowedKeys.has(key));
18935
+ if (unexpectedKey !== void 0) {
18936
+ throw new ArgumentError(`parameter "${unexpectedKey}" is not allowed for resource "${resource}".`);
18937
+ }
18938
+ if (candidate.preview !== void 0 && typeof candidate.preview !== "boolean") {
18939
+ throw new ArgumentError("preview must be a boolean when specified.");
18940
+ }
18941
+ const preview = candidate.preview === true;
18942
+ if (preview && definition.previewPath === void 0) {
18943
+ throw new ArgumentError(`preview is not supported for resource "${resource}".`);
18944
+ }
18945
+ const rawLang = candidate.lang;
18946
+ if (rawLang !== void 0) {
18947
+ if (!definition.allowsLang) {
18948
+ throw new ArgumentError(`lang is not allowed for resource "${resource}".`);
18949
+ }
18950
+ if (typeof rawLang !== "string" || !LANG_SET.has(rawLang)) {
18951
+ throw new ArgumentError(`unsupported lang: ${String(rawLang)}.`);
18952
+ }
18953
+ }
18954
+ return {
18955
+ resource: typedResource,
18956
+ preview,
18957
+ lang: rawLang,
18958
+ definition
18959
+ };
18960
+ }
18961
+ function mapKintoneMetadataRequest(request, resolvedAppId, apiBasePath, authType) {
18962
+ assertResolvedAppId(resolvedAppId);
18963
+ assertApiBasePath(apiBasePath);
18964
+ if (authType !== "token" && authType !== "userpass") {
18965
+ throw new ArgumentError(`unsupported auth type: ${String(authType)}.`);
18966
+ }
18967
+ const { resource, preview, lang, definition } = validateRequest(request);
18968
+ if (definition.authCapability === "userpass-only" && authType === "token") {
18969
+ throw new CapabilityError(`resource "${resource}" requires userpass authentication.`);
18970
+ }
18971
+ const params = new URLSearchParams();
18972
+ params.set(definition.appParameter, String(resolvedAppId));
18973
+ if (lang !== void 0) params.set("lang", lang);
18974
+ const pathFragment = preview ? definition.previewPath : definition.productionPath;
18975
+ if (pathFragment === void 0) {
18976
+ throw new ArgumentError(`preview is not supported for resource "${resource}".`);
18977
+ }
18978
+ return {
18979
+ method: "GET",
18980
+ path: `${apiBasePath}${pathFragment}`,
18981
+ params,
18982
+ environment: preview ? "preview" : "production",
18983
+ resource,
18984
+ authCapability: definition.authCapability
18985
+ };
18986
+ }
18987
+
18487
18988
  // src/cli/nodeKintoneClient.ts
18488
18989
  var KintoneApiError = class extends Error {
18489
18990
  constructor(status, code, bodyText) {
@@ -18494,10 +18995,10 @@ var KintoneApiError = class extends Error {
18494
18995
  }
18495
18996
  };
18496
18997
  var SEARCH_ABORTED_HEADER_VALUE = "Filter aborted because of too many search results";
18497
- function createNodeKintoneClient(baseUrl, tokenResolver) {
18998
+ function createNodeKintoneConnection(baseUrl, tokenResolver) {
18498
18999
  const normalizedBaseUrl = baseUrl.replace(/\/+$/, "");
18499
19000
  const apiBasePath = tokenResolver.guestSpaceId && tokenResolver.guestSpaceId > 0 ? `/k/guest/${tokenResolver.guestSpaceId}/v1` : "/k/v1";
18500
- async function requestJsonResponse(path, init, appIdForToken) {
19001
+ async function requestResponse(path, init, appIdForToken) {
18501
19002
  const headers = new Headers(init.headers ?? {});
18502
19003
  if (tokenResolver.auth.type === "token") {
18503
19004
  headers.set("X-Cybozu-API-Token", tokenResolver.auth.resolveToken(appIdForToken));
@@ -18553,13 +19054,68 @@ function createNodeKintoneClient(baseUrl, tokenResolver) {
18553
19054
  }
18554
19055
  const warning = res.headers.get("X-Cybozu-Warning") ?? "";
18555
19056
  return {
18556
- body: await res.json(),
19057
+ response: res,
18557
19058
  searchAborted: warning.includes(SEARCH_ABORTED_HEADER_VALUE)
18558
19059
  };
18559
19060
  }
19061
+ async function requestJsonResponse(path, init, appIdForToken) {
19062
+ const { response, searchAborted } = await requestResponse(path, init, appIdForToken);
19063
+ return {
19064
+ body: await response.json(),
19065
+ searchAborted
19066
+ };
19067
+ }
18560
19068
  async function requestJson(path, init, appIdForToken) {
18561
19069
  return (await requestJsonResponse(path, init, appIdForToken)).body;
18562
19070
  }
19071
+ async function requestCappedMetadataJson(path, init, appIdForToken) {
19072
+ const { response } = await requestResponse(path, init, appIdForToken);
19073
+ const contentLength = response.headers.get("Content-Length");
19074
+ if (contentLength !== null && /^\d+$/.test(contentLength.trim())) {
19075
+ const declaredBytes = Number(contentLength);
19076
+ if (declaredBytes > KINTONE_METADATA_MAX_RESPONSE_BYTES) {
19077
+ try {
19078
+ await response.body?.cancel();
19079
+ } catch {
19080
+ }
19081
+ throw new ResponseTooLargeError(KINTONE_METADATA_MAX_RESPONSE_BYTES, declaredBytes);
19082
+ }
19083
+ }
19084
+ const chunks = [];
19085
+ let responseBytes = 0;
19086
+ if (response.body !== null) {
19087
+ const reader = response.body.getReader();
19088
+ while (true) {
19089
+ const { done, value } = await reader.read();
19090
+ if (done) break;
19091
+ responseBytes += value.byteLength;
19092
+ if (responseBytes > KINTONE_METADATA_MAX_RESPONSE_BYTES) {
19093
+ try {
19094
+ await reader.cancel();
19095
+ } catch {
19096
+ }
19097
+ throw new ResponseTooLargeError(KINTONE_METADATA_MAX_RESPONSE_BYTES, responseBytes);
19098
+ }
19099
+ chunks.push(value);
19100
+ }
19101
+ }
19102
+ const bytes = new Uint8Array(responseBytes);
19103
+ let offset = 0;
19104
+ for (const chunk3 of chunks) {
19105
+ bytes.set(chunk3, offset);
19106
+ offset += chunk3.byteLength;
19107
+ }
19108
+ let data;
19109
+ try {
19110
+ data = JSON.parse(new TextDecoder("utf-8").decode(bytes));
19111
+ } catch (cause) {
19112
+ throw new InvalidJsonResponseError(cause);
19113
+ }
19114
+ if (typeof data !== "object" || data === null || Array.isArray(data)) {
19115
+ throw new InvalidJsonResponseError();
19116
+ }
19117
+ return { data, responseBytes };
19118
+ }
18563
19119
  function shouldRetryWithRecordNumberOrder(path, bodyText) {
18564
19120
  if (!path.includes("/v1/records.json?")) return false;
18565
19121
  if (!bodyText.includes('"code":"CB_IL02"')) return false;
@@ -18579,7 +19135,7 @@ function createNodeKintoneClient(baseUrl, tokenResolver) {
18579
19135
  const nextQuery = encodeURIComponent(rewritten);
18580
19136
  return `${base}query=${nextQuery}${tail.length > 0 ? `&${tail.join("&")}` : ""}`;
18581
19137
  }
18582
- return {
19138
+ const client = {
18583
19139
  async getRecords(params) {
18584
19140
  const queryPart = `query=${encodeURIComponent(params.query)}`;
18585
19141
  const appPart = `app=${encodeURIComponent(String(params.app))}`;
@@ -18751,6 +19307,34 @@ function createNodeKintoneClient(baseUrl, tokenResolver) {
18751
19307
  };
18752
19308
  }
18753
19309
  };
19310
+ const metadataReader = {
19311
+ async getMetadata(request, resolvedAppId) {
19312
+ const plan = mapKintoneMetadataRequest(
19313
+ request,
19314
+ resolvedAppId,
19315
+ apiBasePath,
19316
+ tokenResolver.auth.type
19317
+ );
19318
+ const query = plan.params.toString();
19319
+ const { data, responseBytes } = await requestCappedMetadataJson(
19320
+ `${plan.path}${query.length > 0 ? `?${query}` : ""}`,
19321
+ { method: "GET" },
19322
+ resolvedAppId
19323
+ );
19324
+ return {
19325
+ resource: plan.resource,
19326
+ environment: plan.environment,
19327
+ path: plan.path,
19328
+ params: Object.fromEntries(plan.params.entries()),
19329
+ responseBytes,
19330
+ data
19331
+ };
19332
+ }
19333
+ };
19334
+ return { client, metadataReader };
19335
+ }
19336
+ function createNodeKintoneClient(baseUrl, tokenResolver) {
19337
+ return createNodeKintoneConnection(baseUrl, tokenResolver).client;
18754
19338
  }
18755
19339
 
18756
19340
  // src/node/appProfiles.ts