@voxgig/sdkgen-infrapack 0.0.13 → 0.0.14

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.
@@ -6,6 +6,7 @@ import {
6
6
  opRequestShape, opParams, ownPoint, entityPath,
7
7
  collectDeps, repoInfo, packageName, packageVersion, apiName, envName,
8
8
  authorInfo, contributorList, isAuthActive, isHttpBasicAuth, jsKey, jsProp,
9
+ resolveAuthIn, resolveAuthName, resolveAuthPrefix,
9
10
  SdkGenError,
10
11
  PUBLISHER, PUBLISHER_URL,
11
12
  pointSegments,
@@ -155,16 +156,27 @@ function idSpec(ent: any): { parts: string[], sep: string, from?: Record<string,
155
156
  return null
156
157
  }
157
158
 
158
- return { parts: [rk], sep: idSep(ent) }
159
+ const from = ent?.id?.from
160
+ const path = null != from && 'object' === typeof from ? from[rk] : null
161
+ return {
162
+ parts: [rk],
163
+ sep: idSep(ent),
164
+ ...(null != path && '' !== String(path) ? { from: { [rk]: String(path) } } : {}),
165
+ }
159
166
  }
160
167
 
161
168
 
169
+ // The model's identifier when the load match carries it, else the terminal
170
+ // path parameter, else a lone required query parameter: the rule the SDK's
171
+ // offline transport keys its store by.
162
172
  function recordKey(ent: any): string {
163
173
  const idf = entityIdField(ent)
164
174
  if (null != idf && '' !== idf) {
165
175
  return String(idf)
166
176
  }
167
177
 
178
+ let fallback = ''
179
+
168
180
  for (const opname of ['load', 'remove', 'update']) {
169
181
  const op = (ent.op || {})[opname]
170
182
  if (null == op || 0 === (op.points || []).length) {
@@ -174,11 +186,11 @@ function recordKey(ent: any): string {
174
186
  const canonical = op.points.filter((pt: any) =>
175
187
  null == (pt && pt.q && pt.q['$action']))
176
188
  const point = ownPoint(0 < canonical.length ? canonical : op.points)
177
- const vars = pointSegments(point)
178
- .filter((seg: any) => null != seg.var)
189
+ const segs = pointSegments(point)
190
+ const last = segs[segs.length - 1]
179
191
 
180
- if (0 < vars.length) {
181
- return String(vars[vars.length - 1].var)
192
+ if (null != last && null != last.var) {
193
+ return String(last.var)
182
194
  }
183
195
 
184
196
  const query = (point && point.g && point.g.query) || []
@@ -186,9 +198,43 @@ function recordKey(ent: any): string {
186
198
  if (1 === reqdQuery.length) {
187
199
  return String(reqdQuery[0].n)
188
200
  }
201
+
202
+ // A literal-terminal route names a facet of a record: a last resort.
203
+ if ('' === fallback) {
204
+ const vars = segs.filter((seg: any) => null != seg.var)
205
+ if (0 < vars.length) {
206
+ fallback = String(vars[vars.length - 1].var)
207
+ }
208
+ }
209
+ }
210
+
211
+ return '' !== fallback ? fallback : 'id'
212
+ }
213
+
214
+
215
+ // Does a create have to SEND the record key, or does the API assign it?
216
+ function rkOnCreate(ent: any): boolean {
217
+ const rk = recordKey(ent)
218
+
219
+ if ('id' === rk || 0 < idParts(ent).length || null == (ent.op || {}).create) {
220
+ return false
189
221
  }
190
222
 
191
- return 'id'
223
+ return opRequestShape(ent, 'create').items
224
+ .some((it: any) => it.name === rk && !it.optional)
225
+ }
226
+
227
+
228
+ // Is `<provider>_id` free for this entity, or a name it already uses itself?
229
+ function parkFree(ent: any, parked: string): boolean {
230
+ const taken = new Set<string>([
231
+ recordKey(ent),
232
+ ...idParts(ent),
233
+ ...parentKeys(ent),
234
+ ...Object.values(ent.fields || {}).map((f: any) => String(f.n)),
235
+ ])
236
+
237
+ return !taken.has(parked)
192
238
  }
193
239
 
194
240
 
@@ -335,6 +381,8 @@ const Main = cmp(function Main(props: any) {
335
381
  ops: entityOps(ent),
336
382
  idf: entityIdField(ent),
337
383
  rk: recordKey(ent),
384
+ rkoncreate: rkOnCreate(ent),
385
+ parkfree: parkFree(ent, lower + '_id'),
338
386
  // The composite key, when this API addresses a record by several
339
387
  // path params at once. The doc and test emitters in Extras need the
340
388
  // same answer the handler emitters use: a test that addresses a
@@ -494,6 +542,11 @@ const Main = cmp(function Main(props: any) {
494
542
  // plumbing one anyway produces a credential path that cannot work.
495
543
  authActive: isAuthActive(model),
496
544
  authBasic: isAuthActive(model) && isHttpBasicAuth(model),
545
+ // Where the credential goes, resolved as the SDK's auth stage does.
546
+ authIn: resolveAuthIn(model),
547
+ authName: 'header' === resolveAuthIn(model) ?
548
+ resolveAuthName(model).toLowerCase() : resolveAuthName(model),
549
+ authPrefix: resolveAuthPrefix(model),
497
550
  }
498
551
 
499
552
  // `.gitignore` is EMITTED rather than copied — npm strips that filename
@@ -662,6 +715,8 @@ const PackageJson = cmp(function PackageJson(props: any) {
662
715
  const ProviderSource = cmp(function ProviderSource(props: any) {
663
716
  const { provider } = props
664
717
 
718
+ const translated = provider.entities.filter((e: any) => null != idSpec(e.ent))
719
+
665
720
  Folder({ name: 'src' }, () => {
666
721
  File({ name: `${provider.fileBase}.ts` }, () => {
667
722
  Content(`/* Generated by @voxgig/sdkgen. Do not edit. */
@@ -760,8 +815,8 @@ function ${provider.pluginName}(this: any, options: ${provider.pluginName}Option
760
815
 
761
816
 
762
817
  // The SDK argument for an ACTION on a read cmd: everything the caller sent
763
- // minus Seneca's own directives, with the record key carried across, plus
764
- // the \`$action\` selector the SDK dispatches on.
818
+ // minus Seneca's own directives, with the id translated into the API's own
819
+ // keys, plus the \`$action\` selector the SDK dispatches on.
765
820
  //
766
821
  // WIDER than the canonical argument on purpose. An action route has its own
767
822
  // parameters — GitHub's merge takes commit_title and merge_method, which the
@@ -769,14 +824,21 @@ function ${provider.pluginName}(this: any, options: ${provider.pluginName}Option
769
824
  // required keys would strip the action's whole payload. The SDK still
770
825
  // validates: an action whose own point cannot be built is refused with
771
826
  // \`point_action_invalid\` rather than sent somewhere else.
772
- function actionq(q: any, rk: string, action: string) {
827
+ function actionq(q: any, ${0 === translated.length ? '' : 'name: string, '}action: string) {
773
828
  const out = cleanq(q)
829
+ ${0 === translated.length ? '' : `
830
+ // An action addresses the SAME record the canonical route does, so the id
831
+ // is translated the same way a write translates it: split into the path
832
+ // parameters the API names, under the names it names them by. Sending the
833
+ // joined id as one terminal parameter asks for \`owner0/repo0\` as a repo.
834
+ const own = Object.prototype.hasOwnProperty
835
+ const spec = own.call(ID_SPEC, name) ? ID_SPEC[name] : null
774
836
 
775
- if ('id' !== rk && null != out.id) {
776
- out[rk] = out.id
837
+ if (null != spec && null != out.id) {
838
+ Object.assign(out, splitid(name, out.id, 'action'))
777
839
  delete out.id
778
840
  }
779
-
841
+ `}
780
842
  out.$action = action
781
843
  return out
782
844
  }
@@ -818,6 +880,15 @@ function ${provider.pluginName}(this: any, options: ${provider.pluginName}Option
818
880
  '${provider.pkgName}: ${e.name} ' + cmd + ': ${k} is required'
819
881
  )
820
882
  }
883
+
884
+ // A path parameter is one value. A loaded record can carry an object
885
+ // under the same name, and that must not be sent as a URL segment.
886
+ if ('object' === typeof value) {
887
+ throw new Error(
888
+ '${provider.pkgName}: ${e.name} ' + cmd + ': ${k} must be a single ' +
889
+ 'value to build the request path, not an object'
890
+ )
891
+ }
821
892
  return value
822
893
  }
823
894
 
@@ -827,16 +898,15 @@ function ${provider.pluginName}(this: any, options: ${provider.pluginName}Option
827
898
  })
828
899
  }
829
900
 
830
- const translated = provider.entities.filter((e: any) => null != idSpec(e.ent))
831
-
832
901
  if (0 < translated.length) {
833
902
  const rows = translated.map((e: any) => {
834
903
  const spec: any = idSpec(e.ent)
835
904
  const from = null == spec.from ? '' :
836
905
  `, from: { ${Object.keys(spec.from).sort()
837
906
  .map((k: string) => `${jsKey(k)}: '${spec.from[k]}'`).join(', ')} }`
907
+ const park = false === e.parkfree ? ', park: false' : ''
838
908
  return ` ${jsKey(e.name)}: { parts: [${
839
- spec.parts.map((p: string) => `'${p}'`).join(', ')}], sep: '${spec.sep}'${from} },`
909
+ spec.parts.map((p: string) => `'${p}'`).join(', ')}], sep: '${spec.sep}'${from}${park} },`
840
910
  }).join('\n')
841
911
 
842
912
  Content(` // HOW EACH ENTITY'S id MAPS TO THE API'S OWN KEYS, from the model.
@@ -853,7 +923,9 @@ function ${provider.pluginName}(this: any, options: ${provider.pluginName}Option
853
923
  // field's name: github returns a repo's owner as an OBJECT
854
924
  // (\`owner.login\`) and its name as \`name\`, never \`repo\`.
855
925
  // A part missing here cannot be read back off a response.
856
- const ID_SPEC: Record<string, { parts: string[], sep: string, from?: Record<string, string> }> = {
926
+ // \`park\` false where \`${provider.lower}_id\` is a name this entity
927
+ // already uses, so the API's own id is left where it is.
928
+ const ID_SPEC: Record<string, { parts: string[], sep: string, from?: Record<string, string>, park?: boolean }> = {
857
929
  ${rows}
858
930
  }
859
931
 
@@ -904,7 +976,7 @@ ${rows}
904
976
  // THE ADDRESSING KEY WINS over an \`id\` the response already carries. A
905
977
  // response often has both — github's pull has a global database \`id\` and
906
978
  // a repo-scoped \`number\` — and the unrelated one is no use for addressing
907
- // anything. It is kept as \`${provider.lower}_id\` rather than dropped.
979
+ // anything. It is kept as \`${provider.lower}_id\`, unless \`park\` forbids.
908
980
  function joinid(name: string, data: any, vals?: any) {
909
981
  const spec = ID_SPEC[name]
910
982
  if (null == data) {
@@ -930,7 +1002,7 @@ ${rows}
930
1002
  }
931
1003
 
932
1004
  if (null != id) {
933
- if (null != data.id && String(data.id) !== id &&
1005
+ if (false !== spec.park && null != data.id && String(data.id) !== id &&
934
1006
  null == ${jsProp('data', provider.lower + '_id')}) {
935
1007
  ${jsProp('data', provider.lower + '_id')} = data.id
936
1008
  }
@@ -1053,19 +1125,18 @@ ${rows}
1053
1125
  each(provider.entities, (e: any) => {
1054
1126
  const eparts = idParts(e.ent)
1055
1127
  const espec = idSpec(e.ent)
1056
- const guard = (cmd: string, src: string) => {
1057
- const keys = 'save' === cmd ?
1058
- [...new Set([...(e.opParents.create || []), ...(e.opParents.update || [])])].sort() :
1059
- (e.opParents[cmd] || [])
1128
+ // Guards of ONE op: save's create and update branches guard their own.
1129
+ const guard = (opname: string, src: string, label = opname, ind = ' ') => {
1130
+ const keys = e.opParents[opname] || []
1060
1131
 
1061
1132
  return keys
1062
1133
  .filter((k: string) => !eparts.includes(k))
1063
1134
  .map((k: string) =>
1064
- ` ${guardName(e, k)}(${jsProp(src, k)}, '${cmd}')\n`)
1135
+ `${ind}${guardName(e, k)}(${jsProp(src, k)}, '${label}')\n`)
1065
1136
  .join('')
1066
1137
  }
1067
1138
 
1068
- const refuse = (cmd: string) => {
1139
+ const refuse = (cmd: string, ind = ' ') => {
1069
1140
  if (true !== (e.idmisaddressed || {})[cmd]) {
1070
1141
  return ''
1071
1142
  }
@@ -1073,13 +1144,17 @@ ${rows}
1073
1144
  recordKey(e.ent)
1074
1145
  const addresses = addressKeys(e.ent, cmd)
1075
1146
 
1076
- return ` misaddressed('${e.name}', '${cmd}', '${key}', ` +
1147
+ return `${ind}misaddressed('${e.name}', '${cmd}', '${key}', ` +
1077
1148
  `[${addresses.map((k: string) => `'${k}'`).join(', ')}])
1078
1149
  `
1079
1150
  }
1080
1151
 
1081
1152
  const rk = recordKey(e.ent)
1082
1153
 
1154
+ // Named only where there is a spec to translate the id through.
1155
+ const aq = `actionq(msg.q, ${0 === translated.length ? '' :
1156
+ `'${e.name}', `}action$)`
1157
+
1083
1158
  const sdkArg = (opname: string) => {
1084
1159
  const keys = addressKeys(e.ent, opname)
1085
1160
  if (0 === keys.length) {
@@ -1094,23 +1169,24 @@ ${rows}
1094
1169
  `${jsKey(k)}: ${jsProp('q', k === rk ? 'id' : k)}`).join(', ')} }`
1095
1170
  }
1096
1171
 
1097
- // The line that splits the Seneca id into the API's parameters,
1098
- // emitted only where there is one record to address. `list` has none.
1099
- // The entity-options argument that carries the path parameters for a
1100
- // write. Empty for an ordinary entity, which needs no such channel.
1101
- const entArg = 0 === eparts.length ? '' :
1102
- `null == key ? undefined : { match: key }`
1172
+ // Seneca's `id` and the API's key differ: composite, or not called id.
1173
+ const keyed = null != espec
1174
+
1175
+ // The entity-options argument carrying a write's addressing values.
1176
+ const entArg = !keyed ? '' : `null == key ? undefined : { match: key }`
1103
1177
 
1104
1178
  const splitLine = (cmd: string) => 0 === eparts.length ? '' :
1105
- ` const key = splitid('${e.name}', ${'save' === cmd ? 'data.id' : 'q.id'}, '${cmd}')\n`
1179
+ ` const key = splitid('${e.name}', q.id, '${cmd}')\n`
1106
1180
 
1107
- // The data hop, plus the id alias when the API keys the record by
1108
- // something other than `id`. A composite entity passes the addressing
1109
- // values through, because the response may not repeat them.
1181
+ // The data hop, plus the id from the values this request addressed the
1182
+ // record with, which the response need not repeat.
1110
1183
  const out = (expr: string, vals?: string) =>
1111
- null == espec ? `plain(${expr})` :
1184
+ !keyed ? `plain(${expr})` :
1112
1185
  `joinid('${e.name}', plain(${expr})${null == vals ? '' : ', ' + vals})`
1113
1186
 
1187
+ const loadVals = 0 < eparts.length ? 'key' :
1188
+ !keyed ? undefined : `{ ${jsKey(rk)}: q.id }`
1189
+
1114
1190
  const actionBranch = (cmd: string, call: string) => ` const action$ = actionOf(msg)
1115
1191
  if (null != action$) {
1116
1192
  const op$ = actionop(action$, '${e.name}', '${cmd}')
@@ -1124,7 +1200,7 @@ ${call} }
1124
1200
  async function list_${e.name}(this: any, entize: any, msg: any) {
1125
1201
  const q = cleanq(msg.q)
1126
1202
  ${actionBranch('list',
1127
- ` const found = await this.shared.sdk.${e.acc}()[op$](actionq(msg.q, '${rk}', action$))
1203
+ ` const found = await this.shared.sdk.${e.acc}()[op$](${aq})
1128
1204
  return found.map((data: any) => entize(${out('data')}))
1129
1205
  `)}${guard('list', 'q')} const list = await this.shared.sdk.${e.acc}().list(q)
1130
1206
  return list.map((data: any) => entize(${out('data')}))
@@ -1139,10 +1215,10 @@ ${actionBranch('list',
1139
1215
  async function load_${e.name}(this: any, entize: any, msg: any) {
1140
1216
  const q = cleanq(msg.q)
1141
1217
  ${actionBranch('load',
1142
- ` const hit = await ornull(() => this.shared.sdk.${e.acc}()[op$](actionq(msg.q, '${rk}', action$)))
1218
+ ` const hit = await ornull(() => this.shared.sdk.${e.acc}()[op$](${aq}))
1143
1219
  return null == hit ? null : entize(${out('hit')})
1144
1220
  `)}${guard('load', 'q')}${splitLine('load')} const res = await ornull(() => this.shared.sdk.${e.acc}().load(${sdkArg('load')}))
1145
- return null == res ? null : entize(${out('res', 0 < eparts.length ? 'key' : undefined)})
1221
+ return null == res ? null : entize(${out('res', loadVals)})
1146
1222
  }
1147
1223
 
1148
1224
  `)
@@ -1152,22 +1228,19 @@ ${actionBranch('load',
1152
1228
  const hasCreate = e.ops.includes('create')
1153
1229
  const hasUpdate = e.ops.includes('update')
1154
1230
 
1155
- const refuseUpdate = true === (e.idmisaddressed || {}).update ?
1156
- refuse('update') : ''
1231
+ const refuseUpdate = true === (e.idmisaddressed || {}).update
1157
1232
 
1158
- const body = hasCreate && hasUpdate
1159
- ? (('' === refuseUpdate) ? ` const res = null == data.id
1160
- ? await sdk.${e.acc}(${entArg}).create(data)
1161
- : await sdk.${e.acc}(${entArg}).update(data)` : ` if (null != data.id) {
1162
- ${refuseUpdate.replace(/\n$/, '')}
1163
- }
1233
+ const isUpdate = keyed ? 'null != key' : 'null != data.id'
1164
1234
 
1165
- const res = await sdk.${e.acc}(${entArg}).create(data)`)
1166
- : hasCreate
1167
- ? ` const res = await sdk.${e.acc}(${entArg}).create(data)`
1168
- : `${refuseUpdate} const res = await sdk.${e.acc}(${entArg}).update(data)`
1235
+ // Deleting a name the entity owns strips a value the caller supplied.
1236
+ const dropPark = false === e.parkfree ? '' : `
1237
+ // \`${provider.lower}_id\` is this provider's own bookkeeping — the
1238
+ // API's unrelated \`id\`, parked by joinid(). It is not a field of the
1239
+ // API's write schema, so it must not travel in the request body.
1240
+ delete ${jsProp('data', provider.lower + '_id')}
1241
+ `
1169
1242
 
1170
- const compositeSave = 0 < eparts.length ? `
1243
+ const keyBlock = 0 < eparts.length ? `
1171
1244
  // Seneca carries this ${e.name}'s key as one \`id\`; the API addresses
1172
1245
  // the record by ${eparts.map((p: string) => '`' + p + '`').join(' and ')}.
1173
1246
  //
@@ -1186,13 +1259,7 @@ ${actionBranch('load',
1186
1259
  if (null != data.id) {
1187
1260
  key = splitid('${e.name}', data.id, 'save')
1188
1261
  }
1189
-
1190
- // \`${provider.lower}_id\` is this provider's own bookkeeping — the
1191
- // API's unrelated \`id\`, parked by joinid() so it is not lost. It is
1192
- // not a field of the API's write schema, so it must not travel in the
1193
- // request body.
1194
- delete ${jsProp('data', provider.lower + '_id')}
1195
-
1262
+ ${dropPark}
1196
1263
  // AND NEITHER DOES THE JOINED \`id\`. It is Seneca's key for this
1197
1264
  // record, not the API's: a composite ${e.name} is addressed by
1198
1265
  // \`${eparts.join('\` and \`')}\`, which travel as path parameters in
@@ -1201,39 +1268,61 @@ ${actionBranch('load',
1201
1268
  // which matches a request against a stored record, then looked for a
1202
1269
  // record whose own \`id\` was that joined string and found none.
1203
1270
  delete data.id
1204
- ` : ''
1205
-
1206
- const alias = 0 < eparts.length ? '' : 'id' === rk ? '' :
1207
- `
1271
+ ` : !keyed ? '' : `
1208
1272
  // This API keys a ${e.name} by \`${rk}\`; Seneca carries it as \`id\`.
1209
- if (null == ${jsProp('data', rk)} && null != data.id) {
1210
- ${jsProp('data', rk)} = data.id
1273
+ // The key goes on the body under the API's own name, where the route
1274
+ // reads it, and into the match, which the SDK consults first.
1275
+ let key = null
1276
+ if (null != data.id) {
1277
+ key = { ${jsKey(rk)}: data.id }
1278
+ if (null == ${jsProp('data', rk)}) {
1279
+ ${jsProp('data', rk)} = data.id
1280
+ }
1211
1281
  }
1212
-
1213
- // \`${provider.lower}_id\` is this provider's own bookkeeping — the
1214
- // API's unrelated \`id\`, parked by joinid() so it is not lost. It
1215
- // is not a field of the API's write schema, so it must not travel in
1216
- // the request body: a strict API rejects an unknown property, and a
1217
- // lax one may persist it.
1218
- delete ${jsProp('data', provider.lower + '_id')}
1282
+ ${dropPark}
1283
+ // NOR DOES SENECA'S \`id\`. It holds the \`${rk}\` this API addresses
1284
+ // the record by, under a name this API's ${e.name} does not have: sent
1285
+ // on the body it is at best an unknown property, and to a store that
1286
+ // matches a write against the record it names the wrong one.
1287
+ delete data.id
1219
1288
  `
1220
1289
 
1290
+ const saveVals = keyed ? 'key' : undefined
1291
+
1292
+ const call = (opname: string) =>
1293
+ `await sdk.${e.acc}(${entArg}).${opname}(data)`
1294
+
1295
+ const body = hasCreate && hasUpdate
1296
+ ? (!refuseUpdate ? ` let res
1297
+ if (${isUpdate}) {
1298
+ ${guard('update', 'data', 'save', ' ')} res = ${call('update')}
1299
+ }
1300
+ else {
1301
+ ${guard('create', 'data', 'save', ' ')} res = ${call('create')}
1302
+ }` : ` if (${isUpdate}) {
1303
+ ${refuse('update', ' ')} }
1304
+
1305
+ ${guard('create', 'data', 'save')} const res = ${call('create')}`)
1306
+ : hasCreate
1307
+ ? `${guard('create', 'data', 'save')} const res = ${call('create')}`
1308
+ : `${refuse('update')}${guard('update', 'data', 'save')} const res = ${call('update')}`
1309
+
1221
1310
  Content(`
1222
1311
  ${jsProp('entity', e.name)}.cmd.save.action =
1223
1312
  async function save_${e.name}(this: any, entize: any, msg: any) {
1224
1313
  const data = msg.ent.data$(false)
1225
- ${alias} const sdk = this.shared.sdk
1314
+ ${keyBlock} const sdk = this.shared.sdk
1226
1315
 
1227
1316
  ${actionBranch('save',
1228
1317
  ` // The action's OWN payload is the entity's own fields — data$(false)
1229
1318
  // has already dropped every trailing-\`$\` key, \`action$\` included,
1230
1319
  // so \`$action\` is the only thing added here.
1231
1320
  data.$action = action$
1232
- const done = await sdk.${e.acc}()[op$](data)
1233
- return entize(${out('done')})
1234
- `)}${guard('save', 'data')}${compositeSave}${body}
1321
+ const done = await sdk.${e.acc}(${entArg})[op$](data)
1322
+ return entize(${out('done', saveVals)})
1323
+ `)}${body}
1235
1324
 
1236
- return entize(${out('res', 0 < eparts.length ? 'key' : undefined)})
1325
+ return entize(${out('res', saveVals)})
1237
1326
  }
1238
1327
 
1239
1328
  `)
@@ -1245,7 +1334,7 @@ ${actionBranch('save',
1245
1334
  async function remove_${e.name}(this: any, entize: any, msg: any) {
1246
1335
  const q = cleanq(msg.q)
1247
1336
  ${actionBranch('remove',
1248
- ` const gone = await ornull(() => this.shared.sdk.${e.acc}()[op$](actionq(msg.q, '${rk}', action$)))
1337
+ ` const gone = await ornull(() => this.shared.sdk.${e.acc}()[op$](${aq}))
1249
1338
  return null == gone ? null : entize(${out('gone')})
1250
1339
  `)}${'' !== refuse('remove') ? refuse('remove') :
1251
1340
  `${guard('remove', 'q')}${splitLine('remove')} await ornull(() => this.shared.sdk.${e.acc}().remove(${sdkArg('remove')}))
@@ -1405,6 +1494,7 @@ if ('undefined' !== typeof module) {
1405
1494
  export {
1406
1495
  Main,
1407
1496
  recordKey,
1497
+ rkOnCreate,
1408
1498
  cmdActions,
1409
1499
  entityActionList,
1410
1500
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voxgig/sdkgen-infrapack",
3
- "version": "0.0.13",
3
+ "version": "0.0.14",
4
4
  "description": "Infrastructure-provider targets for the Voxgig SDK Generator: Seneca provider.",
5
5
  "type": "commonjs",
6
6
  "license": "MIT",
@@ -3,7 +3,7 @@
3
3
  "package": 1
4
4
  },
5
5
  "name": "@voxgig/sdkgen-infrapack",
6
- "version": "0.0.13",
6
+ "version": "0.0.14",
7
7
  "engines": {
8
8
  "sdkgen": ">=4.23.0"
9
9
  },