zinkee 0.1.33 → 0.1.35

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/README.md CHANGED
@@ -279,13 +279,16 @@ Notes:
279
279
  ### CRUD operations
280
280
 
281
281
  ```bash
282
- # Create
282
+ # Create a single record (--set/--set-json/--raw/--raw-file build one record)
283
283
  zinkee records create projects \
284
284
  --set name="Website Redesign" \
285
285
  --set budget=25000 \
286
286
  --set start-date="2026-01-15T00:00:00.000Z" \
287
287
  --set status=1
288
288
 
289
+ # Create many records from a JSON array file (one object per record; mutually exclusive with the single-record flags)
290
+ zinkee --json records create projects --records-file ./projects.json
291
+
289
292
  # List and query
290
293
  zinkee --json records list projects --limit 50
291
294
  zinkee --json records query projects --limit 10 --sort "_id:desc"
@@ -299,6 +302,11 @@ zinkee --json records get projects <record-uuid>
299
302
  # Update
300
303
  zinkee records update projects <record-uuid> --set status=2
301
304
 
305
+ # Reference fields: pass the target record id (bare UUID or "recordId::label" — the label is
306
+ # ignored) or an exact display value. The server stores the canonical "recordId::displayValue"
307
+ # and rejects unknown references (reason "data_field_reference_not_found").
308
+ zinkee records create deals --set deal-name="Acme renewal" --set customer-ref=<target-record-uuid>
309
+
302
310
  # Delete one or more records (--record is repeatable)
303
311
  zinkee records delete projects --record <record-uuid> --record <record-uuid>
304
312
 
package/dist/index.js CHANGED
@@ -2832,35 +2832,78 @@ var specificExamples = {
2832
2832
  ]),
2833
2833
  "records create": buildCommandExamples([
2834
2834
  {
2835
- description: "Minimal create using just two plain string fields.",
2835
+ description: "Create a single record with --set/--set-json (the single-record flags build one record, sent as a one-element 'records' array).",
2836
2836
  command: `zinkee --json records create contacts --set contact-name="Ada Lovelace" --set contact-email=ada@example.com`,
2837
2837
  raw: `{
2838
- "values": {
2839
- "contact-name": "Ada Lovelace",
2840
- "contact-email": "ada@example.com"
2841
- }
2838
+ "records": [
2839
+ {
2840
+ "contact-name": "Ada Lovelace",
2841
+ "contact-email": "ada@example.com"
2842
+ }
2843
+ ]
2842
2844
  }`,
2843
2845
  response: `{
2844
- "recordId": "550e8400-e29b-41d4-a716-446655440000",
2845
- "values": {
2846
- "contact-name": "Ada Lovelace",
2847
- "contact-email": "ada@example.com"
2848
- }
2846
+ "created": [
2847
+ "550e8400-e29b-41d4-a716-446655440000"
2848
+ ],
2849
+ "errors": []
2849
2850
  }`
2850
2851
  },
2851
2852
  {
2852
- description: "Create a record mixing text, option, number, date, reference and member fields. ReferenceField values must match the target's current targetDisplayField (read it from the target record before writing).",
2853
- command: `zinkee --json records create contacts --set contact-name="Grace Hopper" --set contact-email=grace@example.com --set status=2 --set amount=1999.99 --set due-date=2026-06-01T09:00:00Z --set customer-ref="CUST-12" --set owner=6c8a3e0d-4e5f-4a1b-9c2d-3e4f5a6b7c8d`,
2853
+ description: "Create many records from a JSON array file (one object per record, slug -> value). Best-effort: valid records are created and invalid ones are reported per index in 'errors'. ReferenceField values accept the target record id (a bare UUID, or the compound 'recordId::anything' whose label is ignored) or an exact display value; the server stores the canonical 'recordId::displayValue'.",
2854
+ command: `zinkee --json records create contacts --records-file ./records.json`,
2854
2855
  raw: `{
2855
- "values": {
2856
- "contact-name": "Grace Hopper",
2857
- "contact-email": "grace@example.com",
2858
- "status": 2,
2859
- "amount": 1999.99,
2860
- "due-date": "2026-06-01T09:00:00Z",
2861
- "customer-ref": "CUST-12",
2862
- "owner": "6c8a3e0d-4e5f-4a1b-9c2d-3e4f5a6b7c8d"
2863
- }
2856
+ "records": [
2857
+ {
2858
+ "contact-name": "Ada Lovelace",
2859
+ "contact-email": "ada@example.com"
2860
+ },
2861
+ {
2862
+ "contact-name": "Grace Hopper",
2863
+ "contact-email": "grace@example.com",
2864
+ "status": 2,
2865
+ "amount": 1999.99,
2866
+ "due-date": "2026-06-01T09:00:00Z",
2867
+ "customer-ref": "8ad602a1-f6e3-43f6-9ab2-f1c5afc99621",
2868
+ "owner": "6c8a3e0d-4e5f-4a1b-9c2d-3e4f5a6b7c8d"
2869
+ }
2870
+ ]
2871
+ }`,
2872
+ response: `{
2873
+ "created": [
2874
+ "550e8400-e29b-41d4-a716-446655440000"
2875
+ ],
2876
+ "errors": [
2877
+ {
2878
+ "index": 1,
2879
+ "reason": "record_field_not_found",
2880
+ "message": "Field 'contact-emial' was not found in schema '2eb8bdcf-6d9c-4fbb-9018-7fa8180f4c5e'.",
2881
+ "action": "Use a valid field slug from the schema and retry."
2882
+ }
2883
+ ]
2884
+ }`
2885
+ },
2886
+ {
2887
+ description: "Set a ReferenceField by the target record id (a bare UUID, or the compound 'recordId::anything' whose label is ignored) or by an exact display value. The server resolves and stores the canonical 'recordId::displayValue'. Unknown references are rejected per index with reason 'data_field_reference_not_found'.",
2888
+ command: `zinkee --json records create deals --set deal-name="Acme renewal" --set customer-ref=00000000-0000-0000-0000-000000000000`,
2889
+ raw: `{
2890
+ "records": [
2891
+ {
2892
+ "deal-name": "Acme renewal",
2893
+ "customer-ref": "00000000-0000-0000-0000-000000000000"
2894
+ }
2895
+ ]
2896
+ }`,
2897
+ response: `{
2898
+ "created": [],
2899
+ "errors": [
2900
+ {
2901
+ "index": 0,
2902
+ "reason": "data_field_reference_not_found",
2903
+ "message": "Referenced record was not found in the target schema.",
2904
+ "action": "Use an existing record id or an existing display value for this reference field."
2905
+ }
2906
+ ]
2864
2907
  }`
2865
2908
  }
2866
2909
  ]),
@@ -2902,6 +2945,22 @@ var specificExamples = {
2902
2945
  command: "zinkee --json records update contacts 550e8400-e29b-41d4-a716-446655440000 --unset contact-email --unset due-date",
2903
2946
  raw: `{
2904
2947
  "unset": ["contact-email", "due-date"]
2948
+ }`
2949
+ },
2950
+ {
2951
+ description: "Set a ReferenceField on an existing record. Pass the target record id (a bare UUID, or the compound 'recordId::anything' whose label is ignored) or an exact display value; the response shows the canonical 'recordId::displayValue' the server stored. If the reference doesn't exist the whole update is rejected with reason 'data_field_reference_not_found'.",
2952
+ command: "zinkee --json records update deals 550e8400-e29b-41d4-a716-446655440000 --set customer-ref=8ad602a1-f6e3-43f6-9ab2-f1c5afc99621",
2953
+ raw: `{
2954
+ "set": {
2955
+ "customer-ref": "8ad602a1-f6e3-43f6-9ab2-f1c5afc99621"
2956
+ }
2957
+ }`,
2958
+ response: `{
2959
+ "recordId": "550e8400-e29b-41d4-a716-446655440000",
2960
+ "values": {
2961
+ "deal-name": "Acme renewal",
2962
+ "customer-ref": "8ad602a1-f6e3-43f6-9ab2-f1c5afc99621::Acme Corp"
2963
+ }
2905
2964
  }`
2906
2965
  }
2907
2966
  ]),
@@ -10735,10 +10794,10 @@ var RecordsApi = class {
10735
10794
  `/api/v2/schemas/${selectorValue8(schema)}/records/${selectorValue8(record)}`
10736
10795
  );
10737
10796
  }
10738
- createRecord(schema, input) {
10797
+ createRecords(schema, records) {
10739
10798
  return this.client.requestJson(
10740
10799
  `/api/v2/schemas/${selectorValue8(schema)}/records`,
10741
- jsonOptions6(input, "POST")
10800
+ jsonOptions6({ records }, "POST")
10742
10801
  );
10743
10802
  }
10744
10803
  updateRecord(schema, record, input) {
@@ -11140,7 +11199,60 @@ function buildRecordQueryInput(options, allowRaw) {
11140
11199
  }
11141
11200
  return input;
11142
11201
  }
11143
- function buildRecordCreateInput(options) {
11202
+ function readRecordsFromFile(path) {
11203
+ let contents;
11204
+ try {
11205
+ contents = readFileSync8(path, "utf8");
11206
+ } catch (error) {
11207
+ const message = error instanceof Error ? error.message : "Unable to read file.";
11208
+ throw new CliError(
11209
+ "invalid_cli_usage",
11210
+ `Failed to read records from ${path}: ${message}`
11211
+ );
11212
+ }
11213
+ let parsed;
11214
+ try {
11215
+ parsed = JSON.parse(contents);
11216
+ } catch (error) {
11217
+ const message = error instanceof Error ? error.message : "Invalid JSON.";
11218
+ throw new CliError(
11219
+ "invalid_cli_usage",
11220
+ `Failed to parse JSON from --records-file ${path}: ${message}`
11221
+ );
11222
+ }
11223
+ if (!Array.isArray(parsed)) {
11224
+ throw new CliError(
11225
+ "invalid_cli_usage",
11226
+ `Expected --records-file ${path} to contain a JSON array of record objects.`
11227
+ );
11228
+ }
11229
+ if (parsed.length === 0) {
11230
+ throw new CliError(
11231
+ "invalid_cli_usage",
11232
+ `--records-file ${path} must contain at least one record.`
11233
+ );
11234
+ }
11235
+ return parsed.map((record, index) => {
11236
+ if (!isJsonObject6(record)) {
11237
+ throw new CliError(
11238
+ "invalid_cli_usage",
11239
+ `Record at index ${index} in --records-file ${path} must be a JSON object.`
11240
+ );
11241
+ }
11242
+ return record;
11243
+ });
11244
+ }
11245
+ function buildCreateRecords(options) {
11246
+ const hasSingleRecordFlags = (options.set?.length ?? 0) > 0 || (options.setJson?.length ?? 0) > 0 || options.raw !== void 0 || options.rawFile !== void 0;
11247
+ if (options.recordsFile !== void 0) {
11248
+ if (hasSingleRecordFlags) {
11249
+ throw new CliError(
11250
+ "invalid_cli_usage",
11251
+ 'Provide either "--records-file" or the single-record flags (--set/--set-json/--raw/--raw-file), not both.'
11252
+ );
11253
+ }
11254
+ return readRecordsFromFile(options.recordsFile);
11255
+ }
11144
11256
  const values = {
11145
11257
  ...readRawObject3(options.raw, options.rawFile),
11146
11258
  ...buildAssignmentObject(options.set, options.setJson)
@@ -11148,10 +11260,10 @@ function buildRecordCreateInput(options) {
11148
11260
  if (isEmptyObject5(values)) {
11149
11261
  throw new CliError(
11150
11262
  "invalid_cli_usage",
11151
- 'Provide record fields via "--set", "--set-json", "--raw", or "--raw-file".'
11263
+ 'Provide record fields via "--set", "--set-json", "--raw", "--raw-file", or load multiple records with "--records-file".'
11152
11264
  );
11153
11265
  }
11154
- return { values };
11266
+ return [values];
11155
11267
  }
11156
11268
  function buildRecordUpdateInput(options) {
11157
11269
  const raw = readRawObject3(options.raw, options.rawFile);
@@ -11274,21 +11386,38 @@ function registerRecordsCommands(program, options = {}) {
11274
11386
  }
11275
11387
  emitTable4(stdout, data);
11276
11388
  });
11277
- records.command("create").description("Create a record").argument("<schema>", "schema uuid or slug", parseUuidOrSlugSelector8).option("--set <field=value>", "set a string field", collectKeyValueAssignments, []).option("--set-json <field=json>", "set a structured field", collectJsonAssignments, []).option("--raw <json>", "raw JSON object payload").option("--raw-file <path>", "path to a raw JSON object payload").action(async function action(schema, commandOptions) {
11389
+ records.command("create").description("Create one or more records").argument("<schema>", "schema uuid or slug", parseUuidOrSlugSelector8).option(
11390
+ "--set <field=value>",
11391
+ "set a string field (reference fields: a record id, 'recordId::label', or an exact display value)",
11392
+ collectKeyValueAssignments,
11393
+ []
11394
+ ).option("--set-json <field=json>", "set a structured field", collectJsonAssignments, []).option("--raw <json>", "raw JSON object payload").option("--raw-file <path>", "path to a raw JSON object payload").option(
11395
+ "--records-file <path>",
11396
+ "path to a JSON array of record objects (mutually exclusive with --set/--set-json/--raw/--raw-file)"
11397
+ ).action(async function action(schema, commandOptions) {
11278
11398
  const { api, schemasApi, json, readOnly } = createRecordsApi(this, filePath);
11279
11399
  ensureWritable7("records create", readOnly, "write");
11400
+ const records2 = buildCreateRecords(commandOptions);
11280
11401
  const resolvedSchema = await resolveSchemaSelector(schemasApi, schema);
11281
- const data = await api.createRecord(
11282
- resolvedSchema,
11283
- buildRecordCreateInput(commandOptions)
11284
- );
11402
+ const data = await api.createRecords(resolvedSchema, records2);
11285
11403
  if (json) {
11286
11404
  emitJson10(stdout, "records create", data, filePath);
11287
11405
  return;
11288
11406
  }
11289
- writeLine10(stdout, `Created record "${getRecordIdentifier(data)}".`);
11407
+ writeLine10(stdout, `Created ${data.created.length} record(s) in schema "${schema.value}".`);
11408
+ if (data.errors.length > 0) {
11409
+ writeLine10(stdout, `${data.errors.length} record(s) rejected:`);
11410
+ for (const error of data.errors) {
11411
+ writeLine10(stdout, ` - index ${error.index}: ${error.message}`);
11412
+ }
11413
+ }
11290
11414
  });
11291
- records.command("update").description("Update a record").argument("<schema>", "schema uuid or slug", parseUuidOrSlugSelector8).argument("<record>", "record uuid or slug", parseUuidOrSlugSelector8).option("--set <field=value>", "set a string field", collectKeyValueAssignments, []).option("--set-json <field=json>", "set a structured field", collectJsonAssignments, []).option("--unset <field>", "unset a field", collectStringValues, []).option("--raw <json>", "raw JSON object of fields to set").option("--raw-file <path>", "path to a JSON object of fields to set").action(async function action(schema, record, commandOptions) {
11415
+ records.command("update").description("Update a record").argument("<schema>", "schema uuid or slug", parseUuidOrSlugSelector8).argument("<record>", "record uuid or slug", parseUuidOrSlugSelector8).option(
11416
+ "--set <field=value>",
11417
+ "set a string field (reference fields: a record id, 'recordId::label', or an exact display value)",
11418
+ collectKeyValueAssignments,
11419
+ []
11420
+ ).option("--set-json <field=json>", "set a structured field", collectJsonAssignments, []).option("--unset <field>", "unset a field", collectStringValues, []).option("--raw <json>", "raw JSON object of fields to set").option("--raw-file <path>", "path to a JSON object of fields to set").action(async function action(schema, record, commandOptions) {
11292
11421
  const { api, schemasApi, json, readOnly } = createRecordsApi(this, filePath);
11293
11422
  ensureWritable7("records update", readOnly, "write");
11294
11423
  const resolvedSchema = await resolveSchemaSelector(schemasApi, schema);