monsqlize 3.0.0 → 3.1.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.
@@ -752,31 +752,51 @@ async function runModelV1Hook(hooksFactory, model, operation, phase, context, ..
752
752
  }
753
753
  return hook(context, ...args);
754
754
  }
755
+ function mapModelSchemaValidationErrors(errors = []) {
756
+ return errors.map((error) => ({
757
+ field: error.path ?? "",
758
+ message: error.message ?? ""
759
+ }));
760
+ }
755
761
  function validateModelSchemaPayload(context, document, options, metadata = {}) {
756
762
  const shouldValidate = context.validateEnabled || options?.validate === true;
757
763
  if (!shouldValidate) {
758
- return;
764
+ return document;
759
765
  }
760
766
  if (options?.skipValidation) {
761
- return;
767
+ return document;
762
768
  }
763
769
  if (!context.schemaCache || !context.schemaValidateFn) {
764
- return;
770
+ return document;
765
771
  }
766
772
  const result = context.schemaValidateFn(context.schemaCache, document);
767
- if (result.valid) {
768
- return;
773
+ if (!result.valid) {
774
+ const errors = mapModelSchemaValidationErrors(result.errors);
775
+ const fields = [...new Set(errors.map((item) => item.field).filter(Boolean))];
776
+ const summary = fields.length > 0 ? ` (${fields.join(", ")})` : "";
777
+ throw withModelErrorMetadata(
778
+ createError(ErrorCodes.VALIDATION_ERROR, `Schema validation failed${summary}`),
779
+ {
780
+ errors,
781
+ ...metadata
782
+ }
783
+ );
769
784
  }
770
- const errors = result.errors ?? [];
771
- const fields = [...new Set(errors.map((item) => item.path ?? item.field).filter(Boolean))];
772
- const summary = fields.length > 0 ? ` (${fields.join(", ")})` : "";
773
- throw withModelErrorMetadata(
774
- createError(ErrorCodes.VALIDATION_ERROR, `Schema validation failed${summary}`),
775
- {
776
- errors,
777
- ...metadata
778
- }
779
- );
785
+ const normalized = result.data === void 0 ? document : result.data;
786
+ if (normalized === null || typeof normalized !== "object" || Array.isArray(normalized)) {
787
+ const errors = [{
788
+ field: "_schema",
789
+ message: "Schema validation returned non-object data for a complete-document write."
790
+ }];
791
+ throw withModelErrorMetadata(
792
+ createError(ErrorCodes.VALIDATION_ERROR, errors[0].message),
793
+ {
794
+ errors,
795
+ ...metadata
796
+ }
797
+ );
798
+ }
799
+ return normalized;
780
800
  }
781
801
  function applyModelSoftDeleteFilter(query, options, softDeleteConfig) {
782
802
  if (!softDeleteConfig?.enabled) {
@@ -982,6 +1002,19 @@ function applyModelReplaceTimestamps(replacement, timestampsConfig, nowFactory)
982
1002
  [timestampsConfig.updatedAt]: nowFactory()
983
1003
  };
984
1004
  }
1005
+ function preserveModelReplaceCreatedAt(original, normalized, timestampsConfig) {
1006
+ if (!timestampsConfig || timestampsConfig.createdAt === false) {
1007
+ return normalized;
1008
+ }
1009
+ const field = timestampsConfig.createdAt;
1010
+ if (normalized[field] !== void 0 || original[field] === void 0) {
1011
+ return normalized;
1012
+ }
1013
+ return {
1014
+ ...normalized,
1015
+ [field]: original[field]
1016
+ };
1017
+ }
985
1018
 
986
1019
  // src/capabilities/model/model-instance-helpers.ts
987
1020
  var DEFAULT_POPULATE_MAX_DEPTH = 5;
@@ -1202,11 +1235,8 @@ function validateModelDocument(runtime, document) {
1202
1235
  const result = runtime.schemaValidateFn(runtime.schemaCache, document ?? {});
1203
1236
  return {
1204
1237
  valid: result.valid,
1205
- errors: (result.errors ?? []).map((error) => ({
1206
- field: error.field ?? error.path ?? "",
1207
- message: error.message ?? ""
1208
- })),
1209
- data: result.data ?? document
1238
+ errors: mapModelSchemaValidationErrors(result.errors),
1239
+ data: result.data === void 0 ? document : result.data
1210
1240
  };
1211
1241
  } catch (error) {
1212
1242
  return {
@@ -1226,44 +1256,87 @@ function applyModelDefaults(definition, document) {
1226
1256
  }
1227
1257
  return payload;
1228
1258
  }
1259
+ function serializeModelWriteDocument(document) {
1260
+ const payload = serializeDocument(document);
1261
+ for (const [key, descriptor] of Object.entries(Object.getOwnPropertyDescriptors(document))) {
1262
+ if (descriptor.get || descriptor.set) {
1263
+ delete payload[key];
1264
+ }
1265
+ }
1266
+ return payload;
1267
+ }
1268
+ function replaceModelDocumentData(document, payload) {
1269
+ for (const [key, descriptor] of Object.entries(Object.getOwnPropertyDescriptors(document))) {
1270
+ if (!descriptor.enumerable || descriptor.get || descriptor.set || typeof descriptor.value === "function") {
1271
+ continue;
1272
+ }
1273
+ if (!Object.prototype.hasOwnProperty.call(payload, key) && descriptor.configurable !== false) {
1274
+ delete document[key];
1275
+ }
1276
+ }
1277
+ for (const [key, value] of Object.entries(payload)) {
1278
+ const descriptor = Object.getOwnPropertyDescriptor(document, key);
1279
+ if (descriptor?.get || descriptor?.set || descriptor?.writable === false) {
1280
+ continue;
1281
+ }
1282
+ document[key] = value;
1283
+ }
1284
+ }
1229
1285
  async function saveModelDocument(collection, document, options = {}) {
1230
1286
  const nowFactory = options.nowFactory ?? (() => /* @__PURE__ */ new Date());
1231
- let payload = serializeDocument(document);
1287
+ let payload = serializeModelWriteDocument(document);
1232
1288
  if (payload._id !== void 0) {
1289
+ const documentId = payload._id;
1233
1290
  if (options.versionConfig?.enabled) {
1234
1291
  const expectedVersion = assertNumericExpectedVersion(payload[options.versionConfig.field], "save");
1235
- const replacement = applyModelReplaceVersion(
1292
+ if (options.schemaValidationContext) {
1293
+ payload = preserveModelReplaceCreatedAt(
1294
+ serializeModelWriteDocument(document),
1295
+ validateModelSchemaPayload(options.schemaValidationContext, payload),
1296
+ options.timestampsConfig ?? null
1297
+ );
1298
+ }
1299
+ const replacement2 = applyModelReplaceVersion(
1236
1300
  applyModelReplaceTimestamps(payload, options.timestampsConfig ?? null, nowFactory),
1237
1301
  options.versionConfig,
1238
1302
  expectedVersion
1239
1303
  );
1240
- if (options.schemaValidationContext) {
1241
- validateModelSchemaPayload(options.schemaValidationContext, replacement);
1242
- }
1243
1304
  const result2 = await collection.replaceOne(
1244
- { _id: payload._id, [options.versionConfig.field]: expectedVersion },
1245
- replacement,
1305
+ { _id: documentId, [options.versionConfig.field]: expectedVersion },
1306
+ replacement2,
1246
1307
  { upsert: false }
1247
1308
  );
1248
1309
  assertModelOptimisticLockMatched(result2, options.versionConfig);
1249
- Object.assign(document, replacement);
1310
+ replaceModelDocumentData(document, replacement2);
1311
+ document._id = documentId;
1250
1312
  return document;
1251
1313
  }
1252
1314
  if (options.schemaValidationContext) {
1253
- validateModelSchemaPayload(options.schemaValidationContext, payload);
1315
+ payload = preserveModelReplaceCreatedAt(
1316
+ serializeModelWriteDocument(document),
1317
+ validateModelSchemaPayload(options.schemaValidationContext, payload),
1318
+ options.timestampsConfig ?? null
1319
+ );
1254
1320
  }
1255
- await collection.replaceOne({ _id: payload._id }, payload, { upsert: true });
1321
+ const replacement = applyModelReplaceTimestamps(
1322
+ payload,
1323
+ options.timestampsConfig ?? null,
1324
+ nowFactory
1325
+ );
1326
+ await collection.replaceOne({ _id: documentId }, replacement, { upsert: true });
1327
+ replaceModelDocumentData(document, replacement);
1328
+ document._id = documentId;
1256
1329
  return document;
1257
1330
  }
1331
+ if (options.schemaValidationContext) {
1332
+ payload = validateModelSchemaPayload(options.schemaValidationContext, payload);
1333
+ }
1258
1334
  payload = applyModelInsertVersion(
1259
1335
  applyModelInsertTimestamps(payload, options.timestampsConfig ?? null, nowFactory),
1260
1336
  options.versionConfig ?? null
1261
1337
  );
1262
- if (options.schemaValidationContext) {
1263
- validateModelSchemaPayload(options.schemaValidationContext, payload);
1264
- }
1265
1338
  const result = await collection.insertOne(payload);
1266
- Object.assign(document, payload);
1339
+ replaceModelDocumentData(document, payload);
1267
1340
  document._id = result.insertedId;
1268
1341
  return document;
1269
1342
  }
@@ -5061,7 +5134,7 @@ async function orchestrateModelInsertOne(context, document, options) {
5061
5134
  } else {
5062
5135
  await invokeStandardOperationHook(context, "insert", "before", { operation: "insertOne", collection: context.collectionName, data: payload });
5063
5136
  }
5064
- validateModelSchemaPayload({
5137
+ payload = validateModelSchemaPayload({
5065
5138
  validateEnabled: context.validateEnabled,
5066
5139
  schemaCache: context.schemaCache,
5067
5140
  schemaValidateFn: context.schemaValidateFn
@@ -5086,23 +5159,23 @@ async function orchestrateModelInsertOne(context, document, options) {
5086
5159
  }
5087
5160
  async function orchestrateModelInsertMany(context, documents, options) {
5088
5161
  const hookContext = {};
5162
+ const docs = (documents ?? []).map((document) => context.applyDefaults(document));
5089
5163
  if (context.hooksFactory) {
5090
- await invokeV1Hook(context, "insert", "before", hookContext, documents);
5164
+ await invokeV1Hook(context, "insert", "before", hookContext, docs);
5091
5165
  } else {
5092
- await invokeStandardOperationHook(context, "insert", "before", { operation: "insertMany", collection: context.collectionName, data: documents });
5166
+ await invokeStandardOperationHook(context, "insert", "before", { operation: "insertMany", collection: context.collectionName, data: docs });
5093
5167
  }
5094
5168
  const resolvedOptions = options ?? {};
5095
- const docs = [];
5096
- for (let index = 0; index < (documents ?? []).length; index++) {
5097
- let doc = context.applyDefaults((documents ?? [])[index]);
5098
- validateModelSchemaPayload({
5169
+ for (let index = 0; index < docs.length; index++) {
5170
+ let doc = docs[index];
5171
+ doc = validateModelSchemaPayload({
5099
5172
  validateEnabled: context.validateEnabled,
5100
5173
  schemaCache: context.schemaCache,
5101
5174
  schemaValidateFn: context.schemaValidateFn
5102
5175
  }, doc, resolvedOptions, { index });
5103
5176
  doc = applyModelInsertTimestamps(doc, context.timestampsConfig, () => context.nowDate());
5104
5177
  doc = applyModelInsertVersion(doc, context.versionConfig);
5105
- docs.push(doc);
5178
+ docs[index] = doc;
5106
5179
  }
5107
5180
  const result = await context.collection.insertMany(docs, options);
5108
5181
  if (context.hooksFactory) {
@@ -5180,17 +5253,22 @@ async function orchestrateModelReplaceOne(context, filter, replacement, options)
5180
5253
  } else {
5181
5254
  await invokeStandardOperationHook(context, "update", "before", { operation: "replaceOne", collection: context.collectionName, filter, update: replacement });
5182
5255
  }
5256
+ let nextReplacement = validateModelSchemaPayload({
5257
+ validateEnabled: context.validateEnabled,
5258
+ schemaCache: context.schemaCache,
5259
+ schemaValidateFn: context.schemaValidateFn
5260
+ }, replacement, options);
5261
+ nextReplacement = preserveModelReplaceCreatedAt(
5262
+ replacement,
5263
+ nextReplacement,
5264
+ context.timestampsConfig
5265
+ );
5183
5266
  const lock = await resolveModelOptimisticLockAsync(context.collection, filter, options, context.versionConfig, "replaceOne");
5184
- const nextReplacement = applyModelReplaceVersion(
5185
- applyModelReplaceTimestamps(replacement, context.timestampsConfig, () => context.nowDate()),
5267
+ nextReplacement = applyModelReplaceVersion(
5268
+ applyModelReplaceTimestamps(nextReplacement, context.timestampsConfig, () => context.nowDate()),
5186
5269
  context.versionConfig,
5187
5270
  lock.expectedVersion
5188
5271
  );
5189
- validateModelSchemaPayload({
5190
- validateEnabled: context.validateEnabled,
5191
- schemaCache: context.schemaCache,
5192
- schemaValidateFn: context.schemaValidateFn
5193
- }, nextReplacement, lock.driverOptions);
5194
5272
  const result = await context.collection.replaceOne(lock.filter, nextReplacement, lock.driverOptions);
5195
5273
  assertModelOptimisticLockMatched(result, context.versionConfig);
5196
5274
  if (context.hooksFactory) {
@@ -5234,17 +5312,22 @@ async function orchestrateModelFindOneAndReplace(context, filter, replacement, o
5234
5312
  } else {
5235
5313
  await invokeStandardOperationHook(context, "update", "before", { operation: "findOneAndReplace", collection: context.collectionName, filter, update: replacement });
5236
5314
  }
5315
+ let nextReplacement = validateModelSchemaPayload({
5316
+ validateEnabled: context.validateEnabled,
5317
+ schemaCache: context.schemaCache,
5318
+ schemaValidateFn: context.schemaValidateFn
5319
+ }, replacement, options);
5320
+ nextReplacement = preserveModelReplaceCreatedAt(
5321
+ replacement,
5322
+ nextReplacement,
5323
+ context.timestampsConfig
5324
+ );
5237
5325
  const lock = await resolveModelOptimisticLockAsync(context.collection, filter, options, context.versionConfig, "findOneAndReplace");
5238
- const nextReplacement = applyModelReplaceVersion(
5239
- applyModelReplaceTimestamps(replacement, context.timestampsConfig, () => context.nowDate()),
5326
+ nextReplacement = applyModelReplaceVersion(
5327
+ applyModelReplaceTimestamps(nextReplacement, context.timestampsConfig, () => context.nowDate()),
5240
5328
  context.versionConfig,
5241
5329
  lock.expectedVersion
5242
5330
  );
5243
- validateModelSchemaPayload({
5244
- validateEnabled: context.validateEnabled,
5245
- schemaCache: context.schemaCache,
5246
- schemaValidateFn: context.schemaValidateFn
5247
- }, nextReplacement, lock.driverOptions);
5248
5331
  const result = await context.extendedCollection().findOneAndReplace(lock.filter, nextReplacement, lock.driverOptions);
5249
5332
  assertModelOptimisticLockDocument(result, context.versionConfig);
5250
5333
  if (context.hooksFactory) {
@@ -5332,23 +5415,24 @@ async function orchestrateModelIncrementOne(context, filter, field, increment, o
5332
5415
  }
5333
5416
  async function orchestrateModelInsertBatch(context, docs, options) {
5334
5417
  const hookContext = {};
5418
+ const docsToInsert = docs.map((doc) => context.applyDefaults(doc));
5335
5419
  if (context.hooksFactory) {
5336
- await invokeV1Hook(context, "insert", "before", hookContext, docs);
5420
+ await invokeV1Hook(context, "insert", "before", hookContext, docsToInsert);
5337
5421
  } else {
5338
- await invokeStandardOperationHook(context, "insert", "before", { operation: "insertBatch", collection: context.collectionName, data: docs });
5422
+ await invokeStandardOperationHook(context, "insert", "before", { operation: "insertBatch", collection: context.collectionName, data: docsToInsert });
5339
5423
  }
5340
5424
  const resolvedOptions = options ?? {};
5341
- const docsToInsert = docs.map((doc, index) => {
5342
- let record = context.applyDefaults(doc);
5343
- validateModelSchemaPayload({
5425
+ for (let index = 0; index < docsToInsert.length; index++) {
5426
+ let record = docsToInsert[index];
5427
+ record = validateModelSchemaPayload({
5344
5428
  validateEnabled: context.validateEnabled,
5345
5429
  schemaCache: context.schemaCache,
5346
5430
  schemaValidateFn: context.schemaValidateFn
5347
5431
  }, record, resolvedOptions, { index });
5348
5432
  record = applyModelInsertTimestamps(record, context.timestampsConfig, () => context.nowDate());
5349
5433
  record = applyModelInsertVersion(record, context.versionConfig);
5350
- return record;
5351
- });
5434
+ docsToInsert[index] = record;
5435
+ }
5352
5436
  const result = await context.extendedCollection().insertBatch(docsToInsert, options);
5353
5437
  if (context.hooksFactory) {
5354
5438
  try {
@@ -6465,9 +6549,28 @@ async function sleep(ms) {
6465
6549
  import { copyFileSync, existsSync, mkdirSync, mkdtempSync, readdirSync, rmSync } from "node:fs";
6466
6550
  import path from "node:path";
6467
6551
  import { MongoClient } from "mongodb";
6468
- var DEFAULT_MEMORY_SERVER_VERSION = "7.0.14";
6552
+
6553
+ // config/mongodb-memory-server.json
6554
+ var mongodb_memory_server_default = {
6555
+ defaultVersion: "7.0.37",
6556
+ requiredVersions: [
6557
+ { label: "MongoDB 7.0", version: "7.0.37" },
6558
+ { label: "MongoDB 8.0", version: "8.0.26" }
6559
+ ],
6560
+ managedDbPathKinds: [
6561
+ "single",
6562
+ "replset",
6563
+ "examples-single",
6564
+ "examples-replset",
6565
+ "probe-single",
6566
+ "probe-replset"
6567
+ ]
6568
+ };
6569
+
6570
+ // src/adapters/mongodb/common/connect.ts
6571
+ var DEFAULT_MEMORY_SERVER_VERSION = mongodb_memory_server_default.defaultVersion;
6469
6572
  var DEFAULT_MEMORY_SERVER_LAUNCH_TIMEOUT_MS = 3e4;
6470
- var MANAGED_DB_PATH_PREFIXES = ["single-", "replset-", "examples-single-", "examples-replset-", "probe-single-", "probe-replset-"];
6573
+ var MANAGED_DB_PATH_PREFIXES = mongodb_memory_server_default.managedDbPathKinds.map((kind) => `${kind}-`);
6471
6574
  var _memoryServerInstance = null;
6472
6575
  var _memoryServerStartPromise = null;
6473
6576
  var _memoryServerCleanupOptions = { doCleanup: true, force: true };
@@ -0,0 +1,11 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "dependencies": [
4
+ { "name": "async-lock", "version": "1.4.1", "license": "MIT", "source": "package-metadata" },
5
+ { "name": "cache-hub", "version": "2.2.4", "license": "Apache-2.0", "source": "package-metadata" },
6
+ { "name": "ioredis", "version": "5.11.1", "license": "MIT", "source": "package-metadata" },
7
+ { "name": "mongodb", "version": "6.21.0", "license": "Apache-2.0", "source": "package-metadata" },
8
+ { "name": "schema-dsl", "version": "3.0.0", "license": "Apache-2.0", "source": "package-metadata" },
9
+ { "name": "ssh2", "version": "1.17.0", "license": "MIT", "source": "LICENSE:d06b5d27bbbbe22c36b1fd88406b1208876e2d37d795f5b8eaed951a459a3111" }
10
+ ]
11
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "monsqlize",
3
- "version": "3.0.0",
3
+ "version": "3.1.0",
4
4
  "description": "TypeScript production data runtime layer for MongoDB today, with cache, transactions, pools, models, sync, and observability",
5
5
  "type": "commonjs",
6
6
  "main": "./dist/cjs/index.cjs",
@@ -25,6 +25,8 @@
25
25
  "dist/**/*.mjs",
26
26
  "dist/**/*.d.ts",
27
27
  "dist/**/*.d.mts",
28
+ "changelogs/v3.1.0.md",
29
+ "changelogs/v3.1.0-rc.0.md",
28
30
  "changelogs/v3.0.0.md",
29
31
  "changelogs/v2.0.7.md",
30
32
  "changelogs/v2.0.6.md",
@@ -38,6 +40,7 @@
38
40
  "MIGRATION.md",
39
41
  "SECURITY.md",
40
42
  "LICENSE",
43
+ "licenses/production-dependencies.json",
41
44
  "CHANGELOG.md"
42
45
  ],
43
46
  "keywords": [
@@ -82,6 +85,18 @@
82
85
  "node": ">=18.0.0"
83
86
  },
84
87
  "scripts": {
88
+ "check:lint-contract": "node scripts/validation/check-lint-contract.cjs",
89
+ "check:coverage-policy": "node scripts/validation/check-coverage-policy.cjs",
90
+ "check:package-budgets": "node scripts/validation/check-package-budgets.cjs",
91
+ "check:production-licenses": "node scripts/validation/check-production-licenses.cjs",
92
+ "check:contributor-contract": "node scripts/validation/check-contributor-contract.cjs",
93
+ "check:dependency-policy": "node scripts/validation/check-dependency-policy.cjs",
94
+ "check:release-metadata": "node scripts/validation/check-release-metadata.cjs",
95
+ "check:doc-claims": "node scripts/validation/check-doc-claims.cjs",
96
+ "check:error-contract": "node scripts/validation/check-error-contract.cjs",
97
+ "check:current-version": "node scripts/validation/check-current-version-terminology.cjs",
98
+ "cleanup:derived": "node scripts/cleanup-derived-artifacts.cjs",
99
+ "cleanup:derived:apply": "node scripts/cleanup-derived-artifacts.cjs --apply --confirm=derived-artifacts",
85
100
  "check:sizes": "node scripts/check-file-sizes.cjs",
86
101
  "check:sizes:strict": "node scripts/check-file-sizes.cjs --strict",
87
102
  "build": "node scripts/build-p1.cjs",
@@ -109,8 +124,8 @@
109
124
  "check:test-language": "node scripts/check-test-language.cjs",
110
125
  "check:docs-examples": "node scripts/validation/check-doc-example-matrix.cjs",
111
126
  "check:release-candidate": "node scripts/check-release-candidate.cjs",
112
- "verify:fast": "npm run lint && npm run check:docs-examples && npm run type-check && npm run check:sizes:strict && npm run test:runtime && npm run test:compatibility && npm run test:refactor-guard && npm run test:refactor-guard:cache",
113
- "verify:full": "npm run lint && npm run check:docs-examples && npm run type-check && npm run check:sizes:strict && npm run test:examples && npm run test:server-matrix",
127
+ "verify:fast": "npm run check:lint-contract && npm run lint && npm run check:contributor-contract && npm run check:dependency-policy && npm run check:release-metadata && npm run check:doc-claims && npm run check:error-contract && npm run check:current-version && npm run check:docs-examples && npm run type-check && npm run check:sizes:strict && npm run test:runtime && npm run check:package-budgets && npm run check:production-licenses && npm run test:compatibility && npm run test:refactor-guard && npm run test:refactor-guard:cache",
128
+ "verify:full": "npm run check:lint-contract && npm run lint && npm run check:doc-claims && npm run check:error-contract && npm run check:current-version && npm run check:docs-examples && npm run type-check && npm run check:sizes:strict && npm run test:examples && npm run test:server-matrix",
114
129
  "verify:release": "npm run verify:full && npm run test:real-env:private",
115
130
  "verify": "npm run verify:full",
116
131
  "release:preflight": "node scripts/release-preflight.cjs",
@@ -128,14 +143,15 @@
128
143
  "mongodb-memory-server": "10.4.3",
129
144
  "sinon": "22.0.0",
130
145
  "tsd": "0.33.0",
131
- "typescript": "5.9.3"
146
+ "typescript": "5.9.3",
147
+ "typescript-eslint": "8.64.0"
132
148
  },
133
149
  "dependencies": {
134
150
  "async-lock": "1.4.1",
135
151
  "cache-hub": "2.2.4",
136
152
  "ioredis": "5.11.1",
137
153
  "mongodb": "6.21.0",
138
- "schema-dsl": "2.1.6",
154
+ "schema-dsl": "3.0.0",
139
155
  "ssh2": "1.17.0"
140
156
  }
141
157
  }