@carto/api-client 0.5.0-alpha.5 → 0.5.0-alpha.6

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.
@@ -3086,10 +3086,10 @@ var WidgetTilesetSource = class extends WidgetSource {
3086
3086
  filters,
3087
3087
  filterOwner
3088
3088
  );
3089
- assertColumn(this._features, column);
3090
3089
  if (!this._features.length) {
3091
3090
  return [];
3092
3091
  }
3092
+ assertColumn(this._features, column);
3093
3093
  return histogram({
3094
3094
  data: filteredFeatures,
3095
3095
  valuesColumns: normalizeColumns(column),
@@ -3276,16 +3276,79 @@ function normalizeColumns(columns) {
3276
3276
 
3277
3277
  // src/widget-sources/widget-tileset-worker-source.ts
3278
3278
  init_cjs_shims();
3279
- var _WidgetTilesetWorkerSource = class _WidgetTilesetWorkerSource extends WidgetSource {
3279
+ var WidgetTilesetWorkerSource = class extends WidgetSource {
3280
3280
  constructor(props) {
3281
3281
  super(props);
3282
- _WidgetTilesetWorkerSource.init();
3283
- _WidgetTilesetWorkerSource.WORKER.postMessage({
3284
- tableName: this.props.tableName,
3282
+ /////////////////////////////////////////////////////////////////////////////
3283
+ // WEB WORKER MANAGEMENT
3284
+ __publicField(this, "_worker", null);
3285
+ __publicField(this, "_workerNextRequestId", 1);
3286
+ }
3287
+ /**
3288
+ * Returns an initialized Worker, to be reused for the lifecycle of this
3289
+ * source instance.
3290
+ */
3291
+ _getWorker() {
3292
+ if (this._worker) {
3293
+ return this._worker;
3294
+ }
3295
+ this._worker = new Worker(
3296
+ new URL("@carto/api-client/worker", importMetaUrl),
3297
+ {
3298
+ type: "module",
3299
+ name: "cartowidgettileset"
3300
+ }
3301
+ );
3302
+ this._worker.postMessage({
3285
3303
  method: "init" /* INIT */,
3286
3304
  params: [this.props]
3287
3305
  });
3306
+ return this._worker;
3288
3307
  }
3308
+ /** Executes a given method on the worker. */
3309
+ _executeWorkerMethod(method, params, signal) {
3310
+ const worker = this._getWorker();
3311
+ const requestId = this._workerNextRequestId++;
3312
+ const options = params[0];
3313
+ if (options?.spatialIndexReferenceViewState) {
3314
+ const { zoom, latitude, longitude } = options.spatialIndexReferenceViewState;
3315
+ options.spatialIndexReferenceViewState = { zoom, latitude, longitude };
3316
+ }
3317
+ let resolve = null;
3318
+ let reject = null;
3319
+ function onMessage(e) {
3320
+ const response = e.data;
3321
+ if (response.requestId !== requestId) return;
3322
+ if (signal?.aborted) {
3323
+ reject(new Error(signal.reason));
3324
+ } else if (response.ok) {
3325
+ resolve(response.result);
3326
+ } else {
3327
+ reject(new Error(response.error));
3328
+ }
3329
+ }
3330
+ function onAbort() {
3331
+ reject(new Error(signal.reason));
3332
+ }
3333
+ worker.addEventListener("message", onMessage);
3334
+ signal?.addEventListener("abort", onAbort);
3335
+ const promise = new Promise((_resolve, _reject) => {
3336
+ resolve = _resolve;
3337
+ reject = _reject;
3338
+ worker.postMessage({
3339
+ requestId,
3340
+ method,
3341
+ params
3342
+ });
3343
+ });
3344
+ void promise.finally(() => {
3345
+ worker.removeEventListener("message", onMessage);
3346
+ signal?.removeEventListener("abort", onAbort);
3347
+ });
3348
+ return promise;
3349
+ }
3350
+ /////////////////////////////////////////////////////////////////////////////
3351
+ // DATA LOADING
3289
3352
  /**
3290
3353
  * Loads features as a list of tiles (typically provided by deck.gl).
3291
3354
  * After tiles are loaded, {@link extractTileFeatures} must be called
@@ -3297,16 +3360,14 @@ var _WidgetTilesetWorkerSource = class _WidgetTilesetWorkerSource extends Widget
3297
3360
  bbox,
3298
3361
  data
3299
3362
  }));
3300
- _WidgetTilesetWorkerSource.WORKER.postMessage({
3301
- tableName: this.props.tableName,
3363
+ this._getWorker().postMessage({
3302
3364
  method: "loadTiles" /* LOAD_TILES */,
3303
3365
  params: [tiles2]
3304
3366
  });
3305
3367
  }
3306
3368
  /** Configures options used to extract features from tiles. */
3307
3369
  setTileFeatureExtractOptions(options) {
3308
- _WidgetTilesetWorkerSource.WORKER.postMessage({
3309
- tableName: this.props.tableName,
3370
+ this._getWorker().postMessage({
3310
3371
  type: "setTileFeatureExtractOptions" /* SET_TILE_FEATURE_EXTRACT_OPTIONS */,
3311
3372
  params: [options]
3312
3373
  });
@@ -3320,12 +3381,13 @@ var _WidgetTilesetWorkerSource = class _WidgetTilesetWorkerSource extends Widget
3320
3381
  geojson,
3321
3382
  spatialFilter
3322
3383
  }) {
3323
- _WidgetTilesetWorkerSource.WORKER.postMessage({
3324
- tableName: this.props.tableName,
3384
+ this._getWorker().postMessage({
3325
3385
  method: "loadGeoJSON" /* LOAD_GEOJSON */,
3326
3386
  params: [{ geojson, spatialFilter }]
3327
3387
  });
3328
3388
  }
3389
+ /////////////////////////////////////////////////////////////////////////////
3390
+ // WIDGETS API
3329
3391
  // eslint-disable-next-line @typescript-eslint/require-await
3330
3392
  async getFeatures() {
3331
3393
  throw new Error("getFeatures not supported for tilesets");
@@ -3335,7 +3397,6 @@ var _WidgetTilesetWorkerSource = class _WidgetTilesetWorkerSource extends Widget
3335
3397
  ...options
3336
3398
  }) {
3337
3399
  return this._executeWorkerMethod(
3338
- this.props.tableName,
3339
3400
  "getFormula" /* GET_FORMULA */,
3340
3401
  [options],
3341
3402
  abortController?.signal
@@ -3346,7 +3407,6 @@ var _WidgetTilesetWorkerSource = class _WidgetTilesetWorkerSource extends Widget
3346
3407
  ...options
3347
3408
  }) {
3348
3409
  return this._executeWorkerMethod(
3349
- this.props.tableName,
3350
3410
  "getHistogram" /* GET_HISTOGRAM */,
3351
3411
  [options],
3352
3412
  abortController?.signal
@@ -3357,7 +3417,6 @@ var _WidgetTilesetWorkerSource = class _WidgetTilesetWorkerSource extends Widget
3357
3417
  ...options
3358
3418
  }) {
3359
3419
  return this._executeWorkerMethod(
3360
- this.props.tableName,
3361
3420
  "getCategories" /* GET_CATEGORIES */,
3362
3421
  [options],
3363
3422
  abortController?.signal
@@ -3368,7 +3427,6 @@ var _WidgetTilesetWorkerSource = class _WidgetTilesetWorkerSource extends Widget
3368
3427
  ...options
3369
3428
  }) {
3370
3429
  return this._executeWorkerMethod(
3371
- this.props.tableName,
3372
3430
  "getScatter" /* GET_SCATTER */,
3373
3431
  [options],
3374
3432
  abortController?.signal
@@ -3379,7 +3437,6 @@ var _WidgetTilesetWorkerSource = class _WidgetTilesetWorkerSource extends Widget
3379
3437
  ...options
3380
3438
  }) {
3381
3439
  return this._executeWorkerMethod(
3382
- this.props.tableName,
3383
3440
  "getTable" /* GET_TABLE */,
3384
3441
  [options],
3385
3442
  abortController?.signal
@@ -3390,7 +3447,6 @@ var _WidgetTilesetWorkerSource = class _WidgetTilesetWorkerSource extends Widget
3390
3447
  ...options
3391
3448
  }) {
3392
3449
  return this._executeWorkerMethod(
3393
- this.props.tableName,
3394
3450
  "getTimeSeries" /* GET_TIME_SERIES */,
3395
3451
  [options],
3396
3452
  abortController?.signal
@@ -3401,58 +3457,12 @@ var _WidgetTilesetWorkerSource = class _WidgetTilesetWorkerSource extends Widget
3401
3457
  ...options
3402
3458
  }) {
3403
3459
  return this._executeWorkerMethod(
3404
- this.props.tableName,
3405
3460
  "getRange" /* GET_RANGE */,
3406
3461
  [options],
3407
3462
  abortController?.signal
3408
3463
  );
3409
3464
  }
3410
- static init() {
3411
- _WidgetTilesetWorkerSource.WORKER = new Worker(
3412
- new URL("@carto/api-client/worker", importMetaUrl),
3413
- {
3414
- type: "module",
3415
- name: "cartowidgettileset"
3416
- }
3417
- );
3418
- }
3419
- _executeWorkerMethod(tableName, method, params, signal) {
3420
- const worker = _WidgetTilesetWorkerSource.WORKER;
3421
- const requestId = _WidgetTilesetWorkerSource._nextRequestID++;
3422
- const options = params[0];
3423
- if (options?.spatialIndexReferenceViewState) {
3424
- const { zoom, latitude, longitude } = options.spatialIndexReferenceViewState;
3425
- options.spatialIndexReferenceViewState = { zoom, latitude, longitude };
3426
- }
3427
- worker.postMessage({
3428
- requestId,
3429
- tableName,
3430
- method,
3431
- params
3432
- });
3433
- return new Promise((resolve, reject) => {
3434
- function listener(e) {
3435
- const response = e.data;
3436
- if (response.requestId !== requestId) return;
3437
- worker.removeEventListener("message", listener);
3438
- if (signal?.aborted) {
3439
- reject(new Error(signal.reason));
3440
- } else if (response.ok) {
3441
- resolve(response.result);
3442
- } else {
3443
- reject(new Error(response.error));
3444
- }
3445
- }
3446
- worker.addEventListener("message", listener);
3447
- });
3448
- }
3449
3465
  };
3450
- /////////////////////////////////////////////////////////////////////////////
3451
- // WEB WORKER MANAGEMENT
3452
- // TODO: Singleton? Pool shared among datasets? One per dataset?
3453
- __publicField(_WidgetTilesetWorkerSource, "WORKER");
3454
- __publicField(_WidgetTilesetWorkerSource, "_nextRequestID", 1);
3455
- var WidgetTilesetWorkerSource = _WidgetTilesetWorkerSource;
3456
3466
 
3457
3467
  // src/sources/h3-query-source.ts
3458
3468
  var h3QuerySource = async function(options) {
@@ -1147,10 +1147,25 @@ declare enum Method {
1147
1147
  }
1148
1148
 
1149
1149
  /**
1150
- * TODO
1150
+ * Wrapper for {@link WidgetTilesetSource}, moving calculations to Web Workers.
1151
+ * When supported, use of both classes is identical.
1152
+ *
1153
+ * To use this wrapper, the application and environment must support ESM Web
1154
+ * Workers. For older build systems based on CommonJS, or in environments like
1155
+ * Node.js, it may be necessary to use {@link WidgetTilesetSource} directly,
1156
+ * and to (optionally) create workers manually in the application.
1151
1157
  */
1152
1158
  declare class WidgetTilesetWorkerSource extends WidgetSource<WidgetTilesetSourceProps> {
1153
1159
  constructor(props: WidgetTilesetSourceProps);
1160
+ protected _worker: Worker | null;
1161
+ protected _workerNextRequestId: number;
1162
+ /**
1163
+ * Returns an initialized Worker, to be reused for the lifecycle of this
1164
+ * source instance.
1165
+ */
1166
+ _getWorker(): Worker;
1167
+ /** Executes a given method on the worker. */
1168
+ _executeWorkerMethod<T>(method: Method, params: unknown[], signal?: AbortSignal): Promise<T>;
1154
1169
  /**
1155
1170
  * Loads features as a list of tiles (typically provided by deck.gl).
1156
1171
  * After tiles are loaded, {@link extractTileFeatures} must be called
@@ -1176,10 +1191,6 @@ declare class WidgetTilesetWorkerSource extends WidgetSource<WidgetTilesetSource
1176
1191
  getTable({ abortController, ...options }: TableRequestOptions): Promise<TableResponse>;
1177
1192
  getTimeSeries({ abortController, ...options }: TimeSeriesRequestOptions): Promise<TimeSeriesResponse>;
1178
1193
  getRange({ abortController, ...options }: RangeRequestOptions): Promise<RangeResponse>;
1179
- protected static WORKER: Worker;
1180
- protected static _nextRequestID: number;
1181
- static init(): void;
1182
- _executeWorkerMethod<T>(tableName: string, method: Method, params: unknown[], signal?: AbortSignal): Promise<T>;
1183
1194
  }
1184
1195
 
1185
1196
  type H3QuerySourceOptions = SourceOptions & QuerySourceOptions & AggregationOptions & FilterOptions;
@@ -1147,10 +1147,25 @@ declare enum Method {
1147
1147
  }
1148
1148
 
1149
1149
  /**
1150
- * TODO
1150
+ * Wrapper for {@link WidgetTilesetSource}, moving calculations to Web Workers.
1151
+ * When supported, use of both classes is identical.
1152
+ *
1153
+ * To use this wrapper, the application and environment must support ESM Web
1154
+ * Workers. For older build systems based on CommonJS, or in environments like
1155
+ * Node.js, it may be necessary to use {@link WidgetTilesetSource} directly,
1156
+ * and to (optionally) create workers manually in the application.
1151
1157
  */
1152
1158
  declare class WidgetTilesetWorkerSource extends WidgetSource<WidgetTilesetSourceProps> {
1153
1159
  constructor(props: WidgetTilesetSourceProps);
1160
+ protected _worker: Worker | null;
1161
+ protected _workerNextRequestId: number;
1162
+ /**
1163
+ * Returns an initialized Worker, to be reused for the lifecycle of this
1164
+ * source instance.
1165
+ */
1166
+ _getWorker(): Worker;
1167
+ /** Executes a given method on the worker. */
1168
+ _executeWorkerMethod<T>(method: Method, params: unknown[], signal?: AbortSignal): Promise<T>;
1154
1169
  /**
1155
1170
  * Loads features as a list of tiles (typically provided by deck.gl).
1156
1171
  * After tiles are loaded, {@link extractTileFeatures} must be called
@@ -1176,10 +1191,6 @@ declare class WidgetTilesetWorkerSource extends WidgetSource<WidgetTilesetSource
1176
1191
  getTable({ abortController, ...options }: TableRequestOptions): Promise<TableResponse>;
1177
1192
  getTimeSeries({ abortController, ...options }: TimeSeriesRequestOptions): Promise<TimeSeriesResponse>;
1178
1193
  getRange({ abortController, ...options }: RangeRequestOptions): Promise<RangeResponse>;
1179
- protected static WORKER: Worker;
1180
- protected static _nextRequestID: number;
1181
- static init(): void;
1182
- _executeWorkerMethod<T>(tableName: string, method: Method, params: unknown[], signal?: AbortSignal): Promise<T>;
1183
1194
  }
1184
1195
 
1185
1196
  type H3QuerySourceOptions = SourceOptions & QuerySourceOptions & AggregationOptions & FilterOptions;
@@ -41,7 +41,7 @@ import {
41
41
  tileFeaturesGeometries,
42
42
  tileFeaturesSpatialIndex,
43
43
  transformToTileCoords
44
- } from "./chunk-V3E7BKVR.js";
44
+ } from "./chunk-LEI5PI5X.js";
45
45
 
46
46
  // src/deck/get-data-filter-extension-props.ts
47
47
  function getDataFilterExtensionProps(filters, filtersLogicalOperator, filterSize) {
@@ -1109,16 +1109,79 @@ var WidgetTableSource = class extends WidgetRemoteSource {
1109
1109
  };
1110
1110
 
1111
1111
  // src/widget-sources/widget-tileset-worker-source.ts
1112
- var _WidgetTilesetWorkerSource = class _WidgetTilesetWorkerSource extends WidgetSource {
1112
+ var WidgetTilesetWorkerSource = class extends WidgetSource {
1113
1113
  constructor(props) {
1114
1114
  super(props);
1115
- _WidgetTilesetWorkerSource.init();
1116
- _WidgetTilesetWorkerSource.WORKER.postMessage({
1117
- tableName: this.props.tableName,
1115
+ /////////////////////////////////////////////////////////////////////////////
1116
+ // WEB WORKER MANAGEMENT
1117
+ __publicField(this, "_worker", null);
1118
+ __publicField(this, "_workerNextRequestId", 1);
1119
+ }
1120
+ /**
1121
+ * Returns an initialized Worker, to be reused for the lifecycle of this
1122
+ * source instance.
1123
+ */
1124
+ _getWorker() {
1125
+ if (this._worker) {
1126
+ return this._worker;
1127
+ }
1128
+ this._worker = new Worker(
1129
+ new URL("@carto/api-client/worker", import.meta.url),
1130
+ {
1131
+ type: "module",
1132
+ name: "cartowidgettileset"
1133
+ }
1134
+ );
1135
+ this._worker.postMessage({
1118
1136
  method: "init" /* INIT */,
1119
1137
  params: [this.props]
1120
1138
  });
1139
+ return this._worker;
1140
+ }
1141
+ /** Executes a given method on the worker. */
1142
+ _executeWorkerMethod(method, params, signal) {
1143
+ const worker = this._getWorker();
1144
+ const requestId = this._workerNextRequestId++;
1145
+ const options = params[0];
1146
+ if (options?.spatialIndexReferenceViewState) {
1147
+ const { zoom, latitude, longitude } = options.spatialIndexReferenceViewState;
1148
+ options.spatialIndexReferenceViewState = { zoom, latitude, longitude };
1149
+ }
1150
+ let resolve = null;
1151
+ let reject = null;
1152
+ function onMessage(e) {
1153
+ const response = e.data;
1154
+ if (response.requestId !== requestId) return;
1155
+ if (signal?.aborted) {
1156
+ reject(new Error(signal.reason));
1157
+ } else if (response.ok) {
1158
+ resolve(response.result);
1159
+ } else {
1160
+ reject(new Error(response.error));
1161
+ }
1162
+ }
1163
+ function onAbort() {
1164
+ reject(new Error(signal.reason));
1165
+ }
1166
+ worker.addEventListener("message", onMessage);
1167
+ signal?.addEventListener("abort", onAbort);
1168
+ const promise = new Promise((_resolve, _reject) => {
1169
+ resolve = _resolve;
1170
+ reject = _reject;
1171
+ worker.postMessage({
1172
+ requestId,
1173
+ method,
1174
+ params
1175
+ });
1176
+ });
1177
+ void promise.finally(() => {
1178
+ worker.removeEventListener("message", onMessage);
1179
+ signal?.removeEventListener("abort", onAbort);
1180
+ });
1181
+ return promise;
1121
1182
  }
1183
+ /////////////////////////////////////////////////////////////////////////////
1184
+ // DATA LOADING
1122
1185
  /**
1123
1186
  * Loads features as a list of tiles (typically provided by deck.gl).
1124
1187
  * After tiles are loaded, {@link extractTileFeatures} must be called
@@ -1130,16 +1193,14 @@ var _WidgetTilesetWorkerSource = class _WidgetTilesetWorkerSource extends Widget
1130
1193
  bbox,
1131
1194
  data
1132
1195
  }));
1133
- _WidgetTilesetWorkerSource.WORKER.postMessage({
1134
- tableName: this.props.tableName,
1196
+ this._getWorker().postMessage({
1135
1197
  method: "loadTiles" /* LOAD_TILES */,
1136
1198
  params: [tiles]
1137
1199
  });
1138
1200
  }
1139
1201
  /** Configures options used to extract features from tiles. */
1140
1202
  setTileFeatureExtractOptions(options) {
1141
- _WidgetTilesetWorkerSource.WORKER.postMessage({
1142
- tableName: this.props.tableName,
1203
+ this._getWorker().postMessage({
1143
1204
  type: "setTileFeatureExtractOptions" /* SET_TILE_FEATURE_EXTRACT_OPTIONS */,
1144
1205
  params: [options]
1145
1206
  });
@@ -1153,12 +1214,13 @@ var _WidgetTilesetWorkerSource = class _WidgetTilesetWorkerSource extends Widget
1153
1214
  geojson,
1154
1215
  spatialFilter
1155
1216
  }) {
1156
- _WidgetTilesetWorkerSource.WORKER.postMessage({
1157
- tableName: this.props.tableName,
1217
+ this._getWorker().postMessage({
1158
1218
  method: "loadGeoJSON" /* LOAD_GEOJSON */,
1159
1219
  params: [{ geojson, spatialFilter }]
1160
1220
  });
1161
1221
  }
1222
+ /////////////////////////////////////////////////////////////////////////////
1223
+ // WIDGETS API
1162
1224
  // eslint-disable-next-line @typescript-eslint/require-await
1163
1225
  async getFeatures() {
1164
1226
  throw new Error("getFeatures not supported for tilesets");
@@ -1168,7 +1230,6 @@ var _WidgetTilesetWorkerSource = class _WidgetTilesetWorkerSource extends Widget
1168
1230
  ...options
1169
1231
  }) {
1170
1232
  return this._executeWorkerMethod(
1171
- this.props.tableName,
1172
1233
  "getFormula" /* GET_FORMULA */,
1173
1234
  [options],
1174
1235
  abortController?.signal
@@ -1179,7 +1240,6 @@ var _WidgetTilesetWorkerSource = class _WidgetTilesetWorkerSource extends Widget
1179
1240
  ...options
1180
1241
  }) {
1181
1242
  return this._executeWorkerMethod(
1182
- this.props.tableName,
1183
1243
  "getHistogram" /* GET_HISTOGRAM */,
1184
1244
  [options],
1185
1245
  abortController?.signal
@@ -1190,7 +1250,6 @@ var _WidgetTilesetWorkerSource = class _WidgetTilesetWorkerSource extends Widget
1190
1250
  ...options
1191
1251
  }) {
1192
1252
  return this._executeWorkerMethod(
1193
- this.props.tableName,
1194
1253
  "getCategories" /* GET_CATEGORIES */,
1195
1254
  [options],
1196
1255
  abortController?.signal
@@ -1201,7 +1260,6 @@ var _WidgetTilesetWorkerSource = class _WidgetTilesetWorkerSource extends Widget
1201
1260
  ...options
1202
1261
  }) {
1203
1262
  return this._executeWorkerMethod(
1204
- this.props.tableName,
1205
1263
  "getScatter" /* GET_SCATTER */,
1206
1264
  [options],
1207
1265
  abortController?.signal
@@ -1212,7 +1270,6 @@ var _WidgetTilesetWorkerSource = class _WidgetTilesetWorkerSource extends Widget
1212
1270
  ...options
1213
1271
  }) {
1214
1272
  return this._executeWorkerMethod(
1215
- this.props.tableName,
1216
1273
  "getTable" /* GET_TABLE */,
1217
1274
  [options],
1218
1275
  abortController?.signal
@@ -1223,7 +1280,6 @@ var _WidgetTilesetWorkerSource = class _WidgetTilesetWorkerSource extends Widget
1223
1280
  ...options
1224
1281
  }) {
1225
1282
  return this._executeWorkerMethod(
1226
- this.props.tableName,
1227
1283
  "getTimeSeries" /* GET_TIME_SERIES */,
1228
1284
  [options],
1229
1285
  abortController?.signal
@@ -1234,58 +1290,12 @@ var _WidgetTilesetWorkerSource = class _WidgetTilesetWorkerSource extends Widget
1234
1290
  ...options
1235
1291
  }) {
1236
1292
  return this._executeWorkerMethod(
1237
- this.props.tableName,
1238
1293
  "getRange" /* GET_RANGE */,
1239
1294
  [options],
1240
1295
  abortController?.signal
1241
1296
  );
1242
1297
  }
1243
- static init() {
1244
- _WidgetTilesetWorkerSource.WORKER = new Worker(
1245
- new URL("@carto/api-client/worker", import.meta.url),
1246
- {
1247
- type: "module",
1248
- name: "cartowidgettileset"
1249
- }
1250
- );
1251
- }
1252
- _executeWorkerMethod(tableName, method, params, signal) {
1253
- const worker = _WidgetTilesetWorkerSource.WORKER;
1254
- const requestId = _WidgetTilesetWorkerSource._nextRequestID++;
1255
- const options = params[0];
1256
- if (options?.spatialIndexReferenceViewState) {
1257
- const { zoom, latitude, longitude } = options.spatialIndexReferenceViewState;
1258
- options.spatialIndexReferenceViewState = { zoom, latitude, longitude };
1259
- }
1260
- worker.postMessage({
1261
- requestId,
1262
- tableName,
1263
- method,
1264
- params
1265
- });
1266
- return new Promise((resolve, reject) => {
1267
- function listener(e) {
1268
- const response = e.data;
1269
- if (response.requestId !== requestId) return;
1270
- worker.removeEventListener("message", listener);
1271
- if (signal?.aborted) {
1272
- reject(new Error(signal.reason));
1273
- } else if (response.ok) {
1274
- resolve(response.result);
1275
- } else {
1276
- reject(new Error(response.error));
1277
- }
1278
- }
1279
- worker.addEventListener("message", listener);
1280
- });
1281
- }
1282
1298
  };
1283
- /////////////////////////////////////////////////////////////////////////////
1284
- // WEB WORKER MANAGEMENT
1285
- // TODO: Singleton? Pool shared among datasets? One per dataset?
1286
- __publicField(_WidgetTilesetWorkerSource, "WORKER");
1287
- __publicField(_WidgetTilesetWorkerSource, "_nextRequestID", 1);
1288
- var WidgetTilesetWorkerSource = _WidgetTilesetWorkerSource;
1289
1299
 
1290
1300
  // src/sources/h3-query-source.ts
1291
1301
  var h3QuerySource = async function(options) {
package/build/worker.js CHANGED
@@ -1,19 +1,17 @@
1
1
  import {
2
2
  WidgetTilesetSource
3
- } from "./chunk-V3E7BKVR.js";
3
+ } from "./chunk-LEI5PI5X.js";
4
4
 
5
5
  // src/workers/widget-tileset-worker.ts
6
- var SOURCES_BY_NAME = /* @__PURE__ */ new Map();
6
+ var source;
7
7
  addEventListener("message", (e) => {
8
- const { tableName, method, params, requestId } = e.data;
8
+ const { method, params, requestId } = e.data;
9
9
  if (method === "init" /* INIT */) {
10
- const props = params[0];
11
- SOURCES_BY_NAME.set(tableName, new WidgetTilesetSource(props));
10
+ source = new WidgetTilesetSource(params[0]);
12
11
  return;
13
12
  }
14
- const source = SOURCES_BY_NAME.get(tableName);
15
13
  if (!source) {
16
- const error = `Unknown dataset: ${tableName}`;
14
+ const error = `Cannot execute "${method}" on uninitialized source.`;
17
15
  postMessage({ ok: false, error, requestId });
18
16
  return;
19
17
  }
package/package.json CHANGED
@@ -8,7 +8,7 @@
8
8
  "homepage": "https://github.com/CartoDB/carto-api-client#readme",
9
9
  "author": "Don McCurdy <donmccurdy@carto.com>",
10
10
  "packageManager": "yarn@4.3.1",
11
- "version": "0.5.0-alpha.5",
11
+ "version": "0.5.0-alpha.6",
12
12
  "license": "MIT",
13
13
  "publishConfig": {
14
14
  "access": "public",
@@ -195,12 +195,12 @@ export class WidgetTilesetSource extends WidgetSource<WidgetTilesetSourceProps>
195
195
  filterOwner
196
196
  );
197
197
 
198
- assertColumn(this._features, column);
199
-
200
198
  if (!this._features.length) {
201
199
  return [];
202
200
  }
203
201
 
202
+ assertColumn(this._features, column);
203
+
204
204
  return histogram({
205
205
  data: filteredFeatures,
206
206
  valuesColumns: normalizeColumns(column),
@@ -24,20 +24,119 @@ import {Method} from '../workers/constants.js';
24
24
  import {WorkerRequest, WorkerResponse} from '../workers/types.js';
25
25
 
26
26
  /**
27
- * TODO
27
+ * Wrapper for {@link WidgetTilesetSource}, moving calculations to Web Workers.
28
+ * When supported, use of both classes is identical.
29
+ *
30
+ * To use this wrapper, the application and environment must support ESM Web
31
+ * Workers. For older build systems based on CommonJS, or in environments like
32
+ * Node.js, it may be necessary to use {@link WidgetTilesetSource} directly,
33
+ * and to (optionally) create workers manually in the application.
28
34
  */
29
35
  export class WidgetTilesetWorkerSource extends WidgetSource<WidgetTilesetSourceProps> {
30
36
  constructor(props: WidgetTilesetSourceProps) {
31
37
  super(props);
38
+ }
39
+
40
+ /////////////////////////////////////////////////////////////////////////////
41
+ // WEB WORKER MANAGEMENT
42
+
43
+ protected _worker: Worker | null = null;
44
+ protected _workerNextRequestId = 1;
45
+
46
+ /**
47
+ * Returns an initialized Worker, to be reused for the lifecycle of this
48
+ * source instance.
49
+ */
50
+ _getWorker() {
51
+ if (this._worker) {
52
+ return this._worker;
53
+ }
54
+
55
+ this._worker = new Worker(
56
+ new URL('@carto/api-client/worker', import.meta.url),
57
+ {
58
+ type: 'module',
59
+ name: 'cartowidgettileset',
60
+ }
61
+ );
32
62
 
33
- WidgetTilesetWorkerSource.init();
34
- WidgetTilesetWorkerSource.WORKER.postMessage({
35
- tableName: this.props.tableName,
63
+ this._worker.postMessage({
36
64
  method: Method.INIT,
37
65
  params: [this.props],
38
66
  } as WorkerRequest);
67
+
68
+ return this._worker;
39
69
  }
40
70
 
71
+ /** Executes a given method on the worker. */
72
+ _executeWorkerMethod<T>(
73
+ method: Method,
74
+ params: unknown[],
75
+ signal?: AbortSignal
76
+ ): Promise<T> {
77
+ const worker = this._getWorker();
78
+ const requestId = this._workerNextRequestId++;
79
+
80
+ // TODO: ViewState may contain non-serializable data, which we do not need.
81
+ // Remove this sanitization after sc-469614 is fixed.
82
+ const options = params[0] as any;
83
+ if (options?.spatialIndexReferenceViewState) {
84
+ const {zoom, latitude, longitude} =
85
+ options.spatialIndexReferenceViewState;
86
+ options.spatialIndexReferenceViewState = {zoom, latitude, longitude};
87
+ }
88
+
89
+ let resolve: ((value: T) => void) | null = null;
90
+ let reject: ((reason: any) => void) | null = null;
91
+
92
+ // If worker sends message to main process, check whether it's a response
93
+ // to this request, and whether the request can been aborted. Then resolve
94
+ // or reject the Promise.
95
+ function onMessage(e: MessageEvent) {
96
+ const response = e.data as WorkerResponse;
97
+ if (response.requestId !== requestId) return;
98
+
99
+ if (signal?.aborted) {
100
+ reject!(new Error(signal.reason));
101
+ } else if (response.ok) {
102
+ resolve!(response.result as T);
103
+ } else {
104
+ reject!(new Error(response.error));
105
+ }
106
+ }
107
+
108
+ // If request is aborted by user, immediately reject the Promise.
109
+ function onAbort() {
110
+ reject!(new Error(signal!.reason));
111
+ }
112
+
113
+ worker.addEventListener('message', onMessage);
114
+ signal?.addEventListener('abort', onAbort);
115
+
116
+ // Send the task to the worker, creating a Promise to resolve/reject later.
117
+ const promise = new Promise<T>((_resolve, _reject) => {
118
+ resolve = _resolve;
119
+ reject = _reject;
120
+
121
+ worker.postMessage({
122
+ requestId,
123
+ method,
124
+ params,
125
+ } as WorkerRequest);
126
+ });
127
+
128
+ // Whether the task completes, fails, or aborts: clean up afterward.
129
+ void promise.finally(() => {
130
+ worker.removeEventListener('message', onMessage);
131
+ signal?.removeEventListener('abort', onAbort);
132
+ });
133
+
134
+ return promise;
135
+ }
136
+
137
+ /////////////////////////////////////////////////////////////////////////////
138
+ // DATA LOADING
139
+
41
140
  /**
42
141
  * Loads features as a list of tiles (typically provided by deck.gl).
43
142
  * After tiles are loaded, {@link extractTileFeatures} must be called
@@ -50,8 +149,7 @@ export class WidgetTilesetWorkerSource extends WidgetSource<WidgetTilesetSourceP
50
149
  data,
51
150
  }));
52
151
 
53
- WidgetTilesetWorkerSource.WORKER.postMessage({
54
- tableName: this.props.tableName,
152
+ this._getWorker().postMessage({
55
153
  method: Method.LOAD_TILES,
56
154
  params: [tiles],
57
155
  } as WorkerRequest);
@@ -59,8 +157,7 @@ export class WidgetTilesetWorkerSource extends WidgetSource<WidgetTilesetSourceP
59
157
 
60
158
  /** Configures options used to extract features from tiles. */
61
159
  setTileFeatureExtractOptions(options: TileFeatureExtractOptions) {
62
- WidgetTilesetWorkerSource.WORKER.postMessage({
63
- tableName: this.props.tableName,
160
+ this._getWorker().postMessage({
64
161
  type: Method.SET_TILE_FEATURE_EXTRACT_OPTIONS,
65
162
  params: [options],
66
163
  });
@@ -78,13 +175,15 @@ export class WidgetTilesetWorkerSource extends WidgetSource<WidgetTilesetSourceP
78
175
  geojson: FeatureCollection;
79
176
  spatialFilter: SpatialFilter;
80
177
  }) {
81
- WidgetTilesetWorkerSource.WORKER.postMessage({
82
- tableName: this.props.tableName,
178
+ this._getWorker().postMessage({
83
179
  method: Method.LOAD_GEOJSON,
84
180
  params: [{geojson, spatialFilter}],
85
181
  } as WorkerRequest);
86
182
  }
87
183
 
184
+ /////////////////////////////////////////////////////////////////////////////
185
+ // WIDGETS API
186
+
88
187
  // eslint-disable-next-line @typescript-eslint/require-await
89
188
  override async getFeatures(): Promise<FeaturesResponse> {
90
189
  throw new Error('getFeatures not supported for tilesets');
@@ -95,7 +194,6 @@ export class WidgetTilesetWorkerSource extends WidgetSource<WidgetTilesetSourceP
95
194
  ...options
96
195
  }: FormulaRequestOptions): Promise<FormulaResponse> {
97
196
  return this._executeWorkerMethod(
98
- this.props.tableName,
99
197
  Method.GET_FORMULA,
100
198
  [options],
101
199
  abortController?.signal
@@ -107,7 +205,6 @@ export class WidgetTilesetWorkerSource extends WidgetSource<WidgetTilesetSourceP
107
205
  ...options
108
206
  }: HistogramRequestOptions): Promise<HistogramResponse> {
109
207
  return this._executeWorkerMethod(
110
- this.props.tableName,
111
208
  Method.GET_HISTOGRAM,
112
209
  [options],
113
210
  abortController?.signal
@@ -119,7 +216,6 @@ export class WidgetTilesetWorkerSource extends WidgetSource<WidgetTilesetSourceP
119
216
  ...options
120
217
  }: CategoryRequestOptions): Promise<CategoryResponse> {
121
218
  return this._executeWorkerMethod(
122
- this.props.tableName,
123
219
  Method.GET_CATEGORIES,
124
220
  [options],
125
221
  abortController?.signal
@@ -131,7 +227,6 @@ export class WidgetTilesetWorkerSource extends WidgetSource<WidgetTilesetSourceP
131
227
  ...options
132
228
  }: ScatterRequestOptions): Promise<ScatterResponse> {
133
229
  return this._executeWorkerMethod(
134
- this.props.tableName,
135
230
  Method.GET_SCATTER,
136
231
  [options],
137
232
  abortController?.signal
@@ -143,7 +238,6 @@ export class WidgetTilesetWorkerSource extends WidgetSource<WidgetTilesetSourceP
143
238
  ...options
144
239
  }: TableRequestOptions): Promise<TableResponse> {
145
240
  return this._executeWorkerMethod(
146
- this.props.tableName,
147
241
  Method.GET_TABLE,
148
242
  [options],
149
243
  abortController?.signal
@@ -155,7 +249,6 @@ export class WidgetTilesetWorkerSource extends WidgetSource<WidgetTilesetSourceP
155
249
  ...options
156
250
  }: TimeSeriesRequestOptions): Promise<TimeSeriesResponse> {
157
251
  return this._executeWorkerMethod(
158
- this.props.tableName,
159
252
  Method.GET_TIME_SERIES,
160
253
  [options],
161
254
  abortController?.signal
@@ -167,72 +260,9 @@ export class WidgetTilesetWorkerSource extends WidgetSource<WidgetTilesetSourceP
167
260
  ...options
168
261
  }: RangeRequestOptions): Promise<RangeResponse> {
169
262
  return this._executeWorkerMethod(
170
- this.props.tableName,
171
263
  Method.GET_RANGE,
172
264
  [options],
173
265
  abortController?.signal
174
266
  );
175
267
  }
176
-
177
- /////////////////////////////////////////////////////////////////////////////
178
- // WEB WORKER MANAGEMENT
179
-
180
- // TODO: Singleton? Pool shared among datasets? One per dataset?
181
- protected static WORKER: Worker;
182
- protected static _nextRequestID = 1;
183
-
184
- static init() {
185
- WidgetTilesetWorkerSource.WORKER = new Worker(
186
- new URL('@carto/api-client/worker', import.meta.url),
187
- {
188
- type: 'module',
189
- name: 'cartowidgettileset',
190
- }
191
- );
192
- }
193
-
194
- _executeWorkerMethod<T>(
195
- tableName: string,
196
- method: Method,
197
- params: unknown[],
198
- signal?: AbortSignal
199
- ): Promise<T> {
200
- const worker = WidgetTilesetWorkerSource.WORKER;
201
- const requestId = WidgetTilesetWorkerSource._nextRequestID++;
202
-
203
- // TODO: ViewState may contain non-serializable data, which we do not need.
204
- // Remove this sanitization after sc-469614 is fixed.
205
- const options = params[0] as any;
206
- if (options?.spatialIndexReferenceViewState) {
207
- const {zoom, latitude, longitude} =
208
- options.spatialIndexReferenceViewState;
209
- options.spatialIndexReferenceViewState = {zoom, latitude, longitude};
210
- }
211
-
212
- worker.postMessage({
213
- requestId,
214
- tableName,
215
- method,
216
- params,
217
- } as WorkerRequest);
218
-
219
- return new Promise((resolve, reject) => {
220
- function listener(e: MessageEvent) {
221
- const response = e.data as WorkerResponse;
222
- if (response.requestId !== requestId) return;
223
-
224
- worker.removeEventListener('message', listener);
225
-
226
- if (signal?.aborted) {
227
- reject(new Error(signal.reason));
228
- } else if (response.ok) {
229
- resolve(response.result as T);
230
- } else {
231
- reject(new Error(response.error));
232
- }
233
- }
234
-
235
- worker.addEventListener('message', listener);
236
- });
237
- }
238
268
  }
@@ -2,7 +2,6 @@ import type {Method} from './constants.js';
2
2
 
3
3
  export type WorkerRequest = {
4
4
  requestId?: number;
5
- tableName: string; // TODO: Table name is not a unique identifier.
6
5
  method: Method;
7
6
  params: unknown[];
8
7
  };
@@ -5,22 +5,25 @@ import {
5
5
  import {Method} from './constants.js';
6
6
  import type {WorkerRequest, WorkerResponse} from './types.js';
7
7
 
8
- // TODO: Cannot rely on tableName as unique ID.
9
- const SOURCES_BY_NAME = new Map<string, WidgetTilesetSource>();
8
+ /*
9
+ * Web Worker, compiled as a separate `@carto/api-client/worker` entrypoint.
10
+ *
11
+ * Workers are scoped to the lifecycle of a single WidgetTilesetWorkerSource
12
+ * instance, representing and executing calculations on a single datasource.
13
+ */
14
+
15
+ let source: WidgetTilesetSource;
10
16
 
11
17
  addEventListener('message', (e) => {
12
- const {tableName, method, params, requestId} = e.data as WorkerRequest;
18
+ const {method, params, requestId} = e.data as WorkerRequest;
13
19
 
14
20
  if (method === Method.INIT) {
15
- const props = params[0] as WidgetTilesetSourceProps;
16
- SOURCES_BY_NAME.set(tableName, new WidgetTilesetSource(props));
21
+ source = new WidgetTilesetSource(params[0] as WidgetTilesetSourceProps);
17
22
  return;
18
23
  }
19
24
 
20
- const source = SOURCES_BY_NAME.get(tableName);
21
-
22
25
  if (!source) {
23
- const error = `Unknown dataset: ${tableName}`;
26
+ const error = `Cannot execute "${method}" on uninitialized source.`;
24
27
  postMessage({ok: false, error, requestId} as WorkerResponse);
25
28
  return;
26
29
  }
@@ -1829,10 +1829,10 @@ var WidgetTilesetSource = class extends WidgetSource {
1829
1829
  filters,
1830
1830
  filterOwner
1831
1831
  );
1832
- assertColumn(this._features, column);
1833
1832
  if (!this._features.length) {
1834
1833
  return [];
1835
1834
  }
1835
+ assertColumn(this._features, column);
1836
1836
  return histogram({
1837
1837
  data: filteredFeatures,
1838
1838
  valuesColumns: normalizeColumns(column),