@larc-iu/plaid-client 0.2.0-alpha.1 → 0.2.0-alpha.2

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/index.d.ts CHANGED
@@ -469,6 +469,7 @@ export const TASKS: {
469
469
  readonly PARSE: 'parse';
470
470
  readonly TRANSCRIBE: 'transcribe';
471
471
  readonly LINK_VOCAB: 'link-vocab';
472
+ readonly ANALYZE: 'analyze';
472
473
  };
473
474
  /** Whether a service serves a task (declared `extras.tasks`, legacy id-prefix fallback). */
474
475
  export function servesTask(service: DiscoveredService, task: string): boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@larc-iu/plaid-client",
3
- "version": "0.2.0-alpha.1",
3
+ "version": "0.2.0-alpha.2",
4
4
  "description": "JavaScript client for the Plaid annotation API",
5
5
  "type": "module",
6
6
  "repository": {
package/src/index.js CHANGED
@@ -16,6 +16,24 @@ import {
16
16
  requestService,
17
17
  } from './services.js';
18
18
 
19
+ // Helper: normalize a document-read `layers` filter to the wire's
20
+ // comma-separated form. Accepts an array of layer ids or a ready-made string;
21
+ // anything empty becomes undefined so no `?layers=` is sent at all.
22
+ function layersParam(layers) {
23
+ if (layers === undefined || layers === null) return undefined;
24
+ const joined = Array.isArray(layers) ? layers.join(',') : String(layers);
25
+ return joined.length > 0 ? joined : undefined;
26
+ }
27
+
28
+ // Helper: normalize an audit `opTypes` filter to the wire's comma-separated
29
+ // form. Accepts an array of op types or a ready-made string; anything empty
30
+ // becomes undefined so no `?op-types=` is sent at all.
31
+ function opTypesParam(opTypes) {
32
+ if (opTypes === undefined || opTypes === null) return undefined;
33
+ const joined = Array.isArray(opTypes) ? opTypes.join(',') : String(opTypes);
34
+ return joined.length > 0 ? joined : undefined;
35
+ }
36
+
19
37
  // Helper: build body object, filtering out undefined values
20
38
  function bodyOf(obj) {
21
39
  const result = {};
@@ -629,10 +647,19 @@ class PlaidClient {
629
647
  * @param {string} [startTime] - Start of time range
630
648
  * @param {string} [endTime] - End of time range
631
649
  * @param {string} [asOf] - Temporal query timestamp
650
+ * @param {string[]|string} [opTypes] - Only return operations of these
651
+ * types, spelled as in an entry's `op/type` (e.g.
652
+ * `['span-layer/create', 'span-layer/delete']`). An entry appears when
653
+ * one of its operations matches, carrying only the ones that did.
632
654
  */
633
- audit: (userId, startTime, endTime, asOf) =>
655
+ audit: (userId, startTime, endTime, asOf, opTypes) =>
634
656
  listAll(this, `/api/v1/users/${userId}/audit`, {
635
- query: { 'start-time': startTime, 'end-time': endTime, 'as-of': asOf },
657
+ query: {
658
+ 'start-time': startTime,
659
+ 'end-time': endTime,
660
+ 'as-of': asOf,
661
+ 'op-types': opTypesParam(opTypes),
662
+ },
636
663
  }),
637
664
  /**
638
665
  * Get a user by ID
@@ -1005,20 +1032,42 @@ class PlaidClient {
1005
1032
  * @param {string} [startTime] - Start of time range
1006
1033
  * @param {string} [endTime] - End of time range
1007
1034
  * @param {string} [asOf] - Temporal query timestamp
1035
+ * @param {string[]|string} [opTypes] - Only return operations of these
1036
+ * types, spelled as in an entry's `op/type` (e.g.
1037
+ * `['span-layer/create', 'span-layer/delete']`). An entry appears when
1038
+ * one of its operations matches, carrying only the ones that did.
1008
1039
  */
1009
- audit: (documentId, startTime, endTime, asOf) =>
1040
+ audit: (documentId, startTime, endTime, asOf, opTypes) =>
1010
1041
  listAll(this, `/api/v1/documents/${documentId}/audit`, {
1011
- query: { 'start-time': startTime, 'end-time': endTime, 'as-of': asOf },
1042
+ query: {
1043
+ 'start-time': startTime,
1044
+ 'end-time': endTime,
1045
+ 'as-of': asOf,
1046
+ 'op-types': opTypesParam(opTypes),
1047
+ },
1012
1048
  }),
1013
1049
  /**
1014
1050
  * Get a document. Set `includeBody` to true to include all data.
1051
+ *
1052
+ * `layers` narrows a body read to the layers you name (ids of any kind:
1053
+ * text, token, span, or relation). A layer comes back when it is named
1054
+ * or is an ancestor of a named layer, and carries its own
1055
+ * texts/tokens/spans/relations/vocabs only when it is itself named — so
1056
+ * name the text layer too if you also want the text body. An id that is
1057
+ * not a layer of this document's project is an error, not a quietly
1058
+ * smaller response. Requires `includeBody`.
1015
1059
  * @param {string} documentId - The document ID
1016
1060
  * @param {boolean} [includeBody] - Include document body data
1017
1061
  * @param {string} [asOf] - Temporal query timestamp
1062
+ * @param {string[]|string} [layers] - Layer ids to restrict a body read to
1018
1063
  */
1019
- get: (documentId, includeBody, asOf) =>
1064
+ get: (documentId, includeBody, asOf, layers) =>
1020
1065
  this._request('GET', `/api/v1/documents/${documentId}`, {
1021
- queryParams: { 'include-body': includeBody, 'as-of': asOf },
1066
+ queryParams: {
1067
+ 'include-body': includeBody,
1068
+ 'as-of': asOf,
1069
+ layers: layersParam(layers),
1070
+ },
1022
1071
  }),
1023
1072
  /**
1024
1073
  * Delete a document and all data contained.
@@ -1119,10 +1168,19 @@ class PlaidClient {
1119
1168
  * @param {string} [startTime] - Start of time range
1120
1169
  * @param {string} [endTime] - End of time range
1121
1170
  * @param {string} [asOf] - Temporal query timestamp
1171
+ * @param {string[]|string} [opTypes] - Only return operations of these
1172
+ * types, spelled as in an entry's `op/type` (e.g.
1173
+ * `['span-layer/create', 'span-layer/delete']`). An entry appears when
1174
+ * one of its operations matches, carrying only the ones that did.
1122
1175
  */
1123
- audit: (projectId, startTime, endTime, asOf) =>
1176
+ audit: (projectId, startTime, endTime, asOf, opTypes) =>
1124
1177
  listAll(this, `/api/v1/projects/${projectId}/audit`, {
1125
- query: { 'start-time': startTime, 'end-time': endTime, 'as-of': asOf },
1178
+ query: {
1179
+ 'start-time': startTime,
1180
+ 'end-time': endTime,
1181
+ 'as-of': asOf,
1182
+ 'op-types': opTypesParam(opTypes),
1183
+ },
1126
1184
  }),
1127
1185
  /**
1128
1186
  * Link a vocabulary to a project.
@@ -1595,14 +1653,21 @@ class PlaidClient {
1595
1653
  createSSEConnection(this, projectId, onEvent, path),
1596
1654
 
1597
1655
  /**
1598
- * Send a message to project listeners
1656
+ * Send a message to project listeners.
1657
+ *
1658
+ * `data` may be any JSON value and is sent VERBATIM (`rawBody`): a
1659
+ * message payload is opaque application data, like `metadata` and
1660
+ * `config`, so its keys must not be re-cased on the way out. Without
1661
+ * this a key such as `case-marker` would reach listeners as
1662
+ * `caseMarker` in JS and `case_marker` in Python. `listen` restores it
1663
+ * verbatim on the way in.
1599
1664
  * @param {string} projectId - The UUID of the project to send to
1600
1665
  * @param {any} data - The message data to send
1601
1666
  * @returns {Promise<any>} Response from the send operation
1602
1667
  */
1603
1668
  sendMessage: (projectId, data, auditMessage) =>
1604
1669
  this._request('POST', `/api/v1/projects/${projectId}/message`, { auditMessage,
1605
- body: { body: data },
1670
+ rawBody: { body: data },
1606
1671
  }),
1607
1672
 
1608
1673
  /**
@@ -48,6 +48,8 @@ export const TASKS = Object.freeze({
48
48
  TRANSCRIBE: 'transcribe',
49
49
  /** Create vocab links for unlinked tokens. */
50
50
  LINK_VOCAB: 'link-vocab',
51
+ /** Propose an interlinear analysis (morpheme segmentation + glosses) for words. */
52
+ ANALYZE: 'analyze',
51
53
  });
52
54
 
53
55
  /**
package/src/sse.js CHANGED
@@ -1,5 +1,24 @@
1
1
  import { transformResponse } from './transforms.js';
2
2
 
3
+ /**
4
+ * Project a parsed SSE `data:` object onto what a listener callback sees.
5
+ *
6
+ * The envelope is API surface and gets the usual `transformResponse` recasing.
7
+ * A `message` event's `data` is NOT: it is opaque application data (whatever
8
+ * `sendMessage` was handed), so its keys must survive verbatim, exactly as
9
+ * `metadata` and `config` do elsewhere. Without this, a key written
10
+ * `case-marker` reaches a JavaScript listener as `caseMarker` and a Python
11
+ * listener as `case_marker`, so the same broadcast reads differently depending
12
+ * on the reader's language.
13
+ */
14
+ export function eventPayload(eventType, parsed) {
15
+ const payload = transformResponse(parsed);
16
+ if (eventType === 'message' && parsed && typeof parsed === 'object' && 'data' in parsed) {
17
+ payload.data = parsed.data;
18
+ }
19
+ return payload;
20
+ }
21
+
3
22
  /**
4
23
  * Create an SSE connection to the listen endpoint using fetch-based streaming.
5
24
  * Automatically handles heartbeat confirmations and event parsing.
@@ -124,7 +143,7 @@ export function createSSEConnection(client, projectId, onEvent, path) {
124
143
  sendHeartbeatConfirmation();
125
144
  } else {
126
145
  const parsedData = JSON.parse(data);
127
- const shouldStop = onEvent(eventType, transformResponse(parsedData));
146
+ const shouldStop = onEvent(eventType, eventPayload(eventType, parsedData));
128
147
  if (shouldStop === true) {
129
148
  sseConnection.close();
130
149
  return;