@carto/api-client 0.5.30-alpha.b195e7f.118 → 0.5.30-alpha.e460f66.121

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/CHANGELOG.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ - feat(fetchMap): Support line & polygon stroke dash styles (#297)
6
+
5
7
  ### 0.5.30
6
8
 
7
9
  - feat(widgetSources): support `featureIds` / `geometryType` request options to filter widget aggregations by a feature selection without relying on the synthetic `_carto_feature_id` column (#294)
@@ -146,6 +146,7 @@ __export(src_exports, {
146
146
  applySorting: () => applySorting,
147
147
  boundaryQuerySource: () => boundaryQuerySource,
148
148
  boundaryTableSource: () => boundaryTableSource,
149
+ buildAuthHeaders: () => buildAuthHeaders,
149
150
  buildBinaryFeatureFilter: () => buildBinaryFeatureFilter,
150
151
  buildPublicMapUrl: () => buildPublicMapUrl,
151
152
  buildStatsUrl: () => buildStatsUrl,
@@ -164,6 +165,7 @@ __export(src_exports, {
164
165
  filterFunctions: () => filterFunctions,
165
166
  geojsonFeatures: () => geojsonFeatures,
166
167
  getApplicableFilters: () => getApplicableFilters,
168
+ getAuthCredentials: () => getAuthCredentials,
167
169
  getClient: () => getClient,
168
170
  getColorAccessor: () => getColorAccessor,
169
171
  getColumnNameFromGeoColumn: () => getColumnNameFromGeoColumn,
@@ -173,6 +175,7 @@ __export(src_exports, {
173
175
  getIconUrlAccessor: () => getIconUrlAccessor,
174
176
  getLayerDescriptor: () => getLayerDescriptor,
175
177
  getLayerProps: () => getLayerProps,
178
+ getLineStyleAccessor: () => getLineStyleAccessor,
176
179
  getMaxMarkerSize: () => getMaxMarkerSize,
177
180
  getSizeAccessor: () => getSizeAccessor,
178
181
  getSorter: () => getSorter,
@@ -197,6 +200,7 @@ __export(src_exports, {
197
200
  rasterSource: () => rasterSource,
198
201
  removeFilter: () => removeFilter,
199
202
  requestWithParameters: () => requestWithParameters,
203
+ rewriteUrlForSessionMode: () => rewriteUrlForSessionMode,
200
204
  scaleAggregationResLevel: () => scaleAggregationResLevel,
201
205
  scatterPlot: () => scatterPlot,
202
206
  setClient: () => setClient,
@@ -5803,7 +5807,8 @@ var SchemaFieldType = /* @__PURE__ */ ((SchemaFieldType2) => {
5803
5807
  return SchemaFieldType2;
5804
5808
  })(SchemaFieldType || {});
5805
5809
  function isSpatialIndexFilter(spatialFilter) {
5806
- return Array.isArray(spatialFilter.indexes);
5810
+ const filter = spatialFilter;
5811
+ return Array.isArray(filter?.indexes) && ["h3", "h3int", "quadbin"].includes(filter?.type);
5807
5812
  }
5808
5813
 
5809
5814
  // src/utils.ts
@@ -5992,6 +5997,42 @@ init_cjs_shims();
5992
5997
  // src/api/index.ts
5993
5998
  init_cjs_shims();
5994
5999
 
6000
+ // src/api/auth.ts
6001
+ init_cjs_shims();
6002
+ function buildAuthHeaders(options) {
6003
+ if (options.authMode === "session") {
6004
+ if (options.accessToken) {
6005
+ throw new Error(
6006
+ `accessToken must not be provided with authMode: 'session' \u2014 authentication is delegated to the server behind apiBaseUrl`
6007
+ );
6008
+ }
6009
+ return {};
6010
+ }
6011
+ if (!options.accessToken) {
6012
+ throw new Error(
6013
+ `accessToken is required (or pass authMode: 'session' to authenticate via a same-origin session instead)`
6014
+ );
6015
+ }
6016
+ return { Authorization: `Bearer ${options.accessToken}` };
6017
+ }
6018
+ function getAuthCredentials(authMode) {
6019
+ return authMode === "session" ? "same-origin" : void 0;
6020
+ }
6021
+ function rewriteUrlForSessionMode(url, apiBaseUrl) {
6022
+ let origin;
6023
+ try {
6024
+ const parsed = new URL(url);
6025
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
6026
+ return url;
6027
+ }
6028
+ origin = parsed.origin;
6029
+ } catch {
6030
+ return url;
6031
+ }
6032
+ const base = apiBaseUrl.replace(/\/+$/, "");
6033
+ return base + url.slice(origin.length);
6034
+ }
6035
+
5995
6036
  // src/api/carto-api-error.ts
5996
6037
  init_cjs_shims();
5997
6038
  var CartoAPIError = class extends Error {
@@ -6113,7 +6154,8 @@ async function requestWithParameters({
6113
6154
  errorContext,
6114
6155
  maxLengthURL = DEFAULT_MAX_LENGTH_URL,
6115
6156
  localCache,
6116
- signal
6157
+ signal,
6158
+ credentials
6117
6159
  }) {
6118
6160
  parameters = {
6119
6161
  v: V3_MINOR_VERSION,
@@ -6137,8 +6179,9 @@ async function requestWithParameters({
6137
6179
  method: "POST",
6138
6180
  body: JSON.stringify(parameters),
6139
6181
  headers,
6140
- signal
6141
- }) : fetch(url, { headers, signal });
6182
+ signal,
6183
+ ...credentials && { credentials }
6184
+ }) : fetch(url, { headers, signal, ...credentials && { credentials } });
6142
6185
  let response;
6143
6186
  let responseJson;
6144
6187
  const jsonPromise = fetchPromise.then((_response) => {
@@ -6184,8 +6227,19 @@ function createCacheKey(baseUrl, parameters, headers) {
6184
6227
  headers: headerEntries
6185
6228
  });
6186
6229
  }
6230
+ var RELATIVE_ORIGIN = "https://relative.invalid";
6231
+ function parseBaseUrl(baseUrlString) {
6232
+ const isRelative = baseUrlString.startsWith("/") && !baseUrlString.startsWith("//");
6233
+ return {
6234
+ url: new URL(baseUrlString, isRelative ? RELATIVE_ORIGIN : void 0),
6235
+ isRelative
6236
+ };
6237
+ }
6238
+ function serializeBaseUrl(url, isRelative) {
6239
+ return isRelative ? `${url.pathname}${url.search}` : url.toString();
6240
+ }
6187
6241
  function createURLWithParameters(baseUrlString, parameters) {
6188
- const baseUrl = new URL(baseUrlString);
6242
+ const { url: baseUrl, isRelative } = parseBaseUrl(baseUrlString);
6189
6243
  for (const [key, value] of Object.entries(parameters)) {
6190
6244
  if (isPureObject(value) || Array.isArray(value)) {
6191
6245
  baseUrl.searchParams.set(key, JSON.stringify(value));
@@ -6198,16 +6252,16 @@ function createURLWithParameters(baseUrlString, parameters) {
6198
6252
  }
6199
6253
  }
6200
6254
  }
6201
- return baseUrl.toString();
6255
+ return serializeBaseUrl(baseUrl, isRelative);
6202
6256
  }
6203
6257
  function excludeURLParameters(baseUrlString, parameters) {
6204
- const baseUrl = new URL(baseUrlString);
6258
+ const { url: baseUrl, isRelative } = parseBaseUrl(baseUrlString);
6205
6259
  for (const param of parameters) {
6206
6260
  if (baseUrl.searchParams.has(param)) {
6207
6261
  baseUrl.searchParams.delete(param);
6208
6262
  }
6209
6263
  }
6210
- return baseUrl.toString();
6264
+ return serializeBaseUrl(baseUrl, isRelative);
6211
6265
  }
6212
6266
  function clearDefaultRequestCache() {
6213
6267
  DEFAULT_REQUEST_CACHE.clear();
@@ -6235,10 +6289,12 @@ async function baseSource(endpoint, options, urlParameters) {
6235
6289
  }
6236
6290
  const baseUrl = buildSourceUrl(mergedOptions);
6237
6291
  const { clientId, maxLengthURL, localCache } = mergedOptions;
6292
+ const sessionMode = options.authMode === "session";
6238
6293
  const headers = {
6239
- Authorization: `Bearer ${options.accessToken}`,
6294
+ ...buildAuthHeaders(options),
6240
6295
  ...options.headers
6241
6296
  };
6297
+ const credentials = getAuthCredentials(options.authMode);
6242
6298
  const parameters = { client: clientId, ...options.tags, ...urlParameters };
6243
6299
  const errorContext = {
6244
6300
  requestType: "Map instantiation",
@@ -6252,15 +6308,19 @@ async function baseSource(endpoint, options, urlParameters) {
6252
6308
  headers,
6253
6309
  errorContext,
6254
6310
  maxLengthURL,
6255
- localCache
6311
+ localCache,
6312
+ credentials
6256
6313
  });
6257
- const dataUrl = tilejson.url[0];
6314
+ let dataUrl = tilejson.url[0];
6258
6315
  if (cache) {
6259
6316
  cache.value = parseInt(
6260
6317
  new URL(dataUrl).searchParams.get("cache") || "",
6261
6318
  10
6262
6319
  );
6263
6320
  }
6321
+ if (sessionMode) {
6322
+ dataUrl = rewriteUrlForSessionMode(dataUrl, mergedOptions.apiBaseUrl);
6323
+ }
6264
6324
  errorContext.requestType = "Map data";
6265
6325
  const json = await requestWithParameters({
6266
6326
  baseUrl: dataUrl,
@@ -6268,9 +6328,14 @@ async function baseSource(endpoint, options, urlParameters) {
6268
6328
  headers,
6269
6329
  errorContext,
6270
6330
  maxLengthURL,
6271
- localCache
6331
+ localCache,
6332
+ credentials
6272
6333
  });
6273
- if (accessToken) {
6334
+ if (sessionMode) {
6335
+ json.tiles = json.tiles?.map(
6336
+ (template) => rewriteUrlForSessionMode(template, mergedOptions.apiBaseUrl)
6337
+ );
6338
+ } else if (accessToken) {
6274
6339
  json.accessToken = accessToken;
6275
6340
  }
6276
6341
  if (schema) {
@@ -6393,6 +6458,7 @@ function dealWithApiError({
6393
6458
  async function makeCall({
6394
6459
  url,
6395
6460
  accessToken,
6461
+ authMode,
6396
6462
  opts
6397
6463
  }) {
6398
6464
  let response;
@@ -6401,10 +6467,13 @@ async function makeCall({
6401
6467
  try {
6402
6468
  response = await fetch(url.toString(), {
6403
6469
  headers: {
6404
- Authorization: `Bearer ${accessToken}`,
6470
+ ...buildAuthHeaders({ accessToken, authMode }),
6405
6471
  ...isPost && { "Content-Type": "application/json" },
6406
6472
  ...opts.headers
6407
6473
  },
6474
+ ...getAuthCredentials(authMode) && {
6475
+ credentials: getAuthCredentials(authMode)
6476
+ },
6408
6477
  ...isPost && {
6409
6478
  method: opts?.method,
6410
6479
  body: opts?.body
@@ -6448,9 +6517,8 @@ function executeModel(props) {
6448
6517
  )}`
6449
6518
  );
6450
6519
  const { model, source, params, opts } = props;
6451
- const { type, apiVersion, apiBaseUrl, accessToken, connectionName, clientId } = source;
6520
+ const { type, apiVersion, apiBaseUrl, connectionName, clientId } = source;
6452
6521
  assert2(apiBaseUrl, "executeModel: missing apiBaseUrl");
6453
- assert2(accessToken, "executeModel: missing accessToken");
6454
6522
  assert2(apiVersion === V3, "executeModel: SQL Model API requires CARTO 3+");
6455
6523
  assert2(type !== "tileset", "executeModel: Tilesets not supported");
6456
6524
  let url = `${apiBaseUrl}/v3/sql/${connectionName}/model/${model}`;
@@ -6489,6 +6557,7 @@ function executeModel(props) {
6489
6557
  return makeCall({
6490
6558
  url,
6491
6559
  accessToken: source.accessToken,
6560
+ authMode: source.authMode,
6492
6561
  opts: {
6493
6562
  ...opts,
6494
6563
  method: isGet ? "GET" : "POST",
@@ -6615,6 +6684,7 @@ var WidgetRemoteSource = class extends WidgetSource {
6615
6684
  apiBaseUrl: props.apiBaseUrl,
6616
6685
  clientId: props.clientId,
6617
6686
  accessToken: props.accessToken,
6687
+ authMode: props.authMode,
6618
6688
  connectionName: props.connectionName,
6619
6689
  filters: getApplicableFilters(filterOwner, filters || props.filters),
6620
6690
  filtersLogicalOperator: props.filtersLogicalOperator,
@@ -6944,7 +7014,7 @@ var WidgetRemoteSource = class extends WidgetSource {
6944
7014
  url = `${apiBaseUrl}/${apiVersion}/stats/${connectionName}/${data}/${spatialDataColumn}`;
6945
7015
  }
6946
7016
  const headers = {
6947
- Authorization: `Bearer ${this.props.accessToken}`,
7017
+ ...buildAuthHeaders(this.props),
6948
7018
  ...this.props.headers
6949
7019
  };
6950
7020
  const errorContext = {
@@ -6957,7 +7027,8 @@ var WidgetRemoteSource = class extends WidgetSource {
6957
7027
  headers,
6958
7028
  signal,
6959
7029
  errorContext,
6960
- parameters
7030
+ parameters,
7031
+ credentials: getAuthCredentials(this.props.authMode)
6961
7032
  }).then(({ extent: { xmin, ymin, xmax, ymax } }) => ({
6962
7033
  bbox: [xmin, ymin, xmax, ymax]
6963
7034
  }));
@@ -8739,7 +8810,7 @@ var query = async function(options) {
8739
8810
  }
8740
8811
  const baseUrl = buildQueryUrl({ apiBaseUrl, connectionName });
8741
8812
  const headers = {
8742
- Authorization: `Bearer ${options.accessToken}`,
8813
+ ...buildAuthHeaders(options),
8743
8814
  ...options.headers
8744
8815
  };
8745
8816
  const parameters = {
@@ -8761,7 +8832,8 @@ var query = async function(options) {
8761
8832
  errorContext,
8762
8833
  maxLengthURL,
8763
8834
  localCache,
8764
- signal: options.signal
8835
+ signal: options.signal,
8836
+ credentials: getAuthCredentials(options.authMode)
8765
8837
  });
8766
8838
  };
8767
8839
 
@@ -10078,6 +10150,19 @@ function getIconUrlAccessor(field, range, {
10078
10150
  };
10079
10151
  return normalizeAccessor(accessor, data);
10080
10152
  }
10153
+ function getLineStyleAccessor(field, range, data) {
10154
+ const fallback = range.othersDashArray ?? [0, 0];
10155
+ const mapping = {};
10156
+ for (const { value, dashArray } of range.dashArrayMap) {
10157
+ mapping[value] = dashArray;
10158
+ }
10159
+ const accessor = (properties) => mapping[properties[field.name]] ?? fallback;
10160
+ return {
10161
+ accessor: normalizeAccessor(accessor, data),
10162
+ domain: range.dashArrayMap.map(({ value }) => value),
10163
+ range: range.dashArrayMap.map(({ dashArray }) => dashArray)
10164
+ };
10165
+ }
10081
10166
  function getMaxMarkerSize(visConfig, visualChannels) {
10082
10167
  const { radiusRange, radius, sizeMaxPixels } = visConfig;
10083
10168
  const { radiusField, sizeField } = visualChannels;
@@ -10791,6 +10876,10 @@ function createChannelProps(id, layerType, config2, visualChannels, data, datase
10791
10876
  const result = {};
10792
10877
  const updateTriggers = {};
10793
10878
  const scales = {};
10879
+ const isVectorTile = layerType === "mvt" || layerType === "tileset";
10880
+ const geometry = data.tilestats?.layers?.[0]?.geometry;
10881
+ const isLine = geometry === "Line" || geometry === "LineString" || geometry === "MultiLineString";
10882
+ const isPolygon = geometry === "Polygon" || geometry === "MultiPolygon";
10794
10883
  {
10795
10884
  const { colorField, colorScale } = visualChannels;
10796
10885
  const { colorRange } = visConfig;
@@ -10951,6 +11040,43 @@ function createChannelProps(id, layerType, config2, visualChannels, data, datase
10951
11040
  };
10952
11041
  }
10953
11042
  }
11043
+ {
11044
+ const strokeVisible = isLine || isPolygon && Boolean(visConfig.stroked);
11045
+ if (isVectorTile && strokeVisible) {
11046
+ const { lineStyleField, lineStyleScale } = visualChannels;
11047
+ const { lineStyleRange } = visConfig;
11048
+ if (visConfig.lineStyle && visConfig.lineStyle !== "solid") {
11049
+ if (visConfig.lineStyle === "dotted") {
11050
+ result.lineCapRounded = true;
11051
+ }
11052
+ result.lineStyle = visConfig.lineStyle;
11053
+ if (visConfig.dashArray) {
11054
+ result.dashArray = visConfig.dashArray;
11055
+ result.getDashArray = visConfig.dashArray;
11056
+ }
11057
+ }
11058
+ if (lineStyleField && lineStyleScale && lineStyleRange) {
11059
+ const { accessor, ...scaleProps } = getLineStyleAccessor(
11060
+ lineStyleField,
11061
+ lineStyleRange,
11062
+ data
11063
+ );
11064
+ result.getDashArray = accessor;
11065
+ scales.lineStyle = updateTriggers.getDashArray = {
11066
+ field: lineStyleField,
11067
+ type: lineStyleScale,
11068
+ ...scaleProps
11069
+ };
11070
+ const dashArrays = [
11071
+ ...lineStyleRange.dashArrayMap.map(({ dashArray }) => dashArray),
11072
+ ...lineStyleRange.othersDashArray ? [lineStyleRange.othersDashArray] : []
11073
+ ];
11074
+ if (dashArrays.some(([dash]) => dash === 0)) {
11075
+ result.lineCapRounded = true;
11076
+ }
11077
+ }
11078
+ }
11079
+ }
10954
11080
  {
10955
11081
  const { heightField, heightScale } = visualChannels;
10956
11082
  const { enable3d, heightRange } = visConfig;
@@ -11079,9 +11205,7 @@ function createChannelProps(id, layerType, config2, visualChannels, data, datase
11079
11205
  } = secondaryLabel || {};
11080
11206
  result.getText = mainLabel.field && getTextAccessor(mainLabel.field, data);
11081
11207
  const getSecondaryText = secondaryField && getTextAccessor(secondaryField, data);
11082
- const geometry = data.tilestats?.layers?.[0]?.geometry;
11083
- const isLineOrPolygon = geometry === "Polygon" || geometry === "MultiPolygon" || geometry === "Line" || geometry === "LineString" || geometry === "MultiLineString";
11084
- if (isLineOrPolygon && (layerType === "tileset" || layerType === "mvt")) {
11208
+ if ((isLine || isPolygon) && isVectorTile) {
11085
11209
  const uniqueIdProperty = visConfig.textLabelUniqueIdField;
11086
11210
  result.autoLabels = uniqueIdProperty ? { uniqueIdProperty } : true;
11087
11211
  result.pointType = "text";
@@ -11118,6 +11242,9 @@ function createChannelProps(id, layerType, config2, visualChannels, data, datase
11118
11242
  };
11119
11243
  }
11120
11244
  function createLoadOptions(accessToken) {
11245
+ if (!accessToken) {
11246
+ return { loadOptions: { fetch: { credentials: "same-origin" } } };
11247
+ }
11121
11248
  return {
11122
11249
  loadOptions: { fetch: { headers: { Authorization: `Bearer ${accessToken}` } } }
11123
11250
  };
@@ -11820,6 +11947,7 @@ function hashBuckets(initialCount) {
11820
11947
  applySorting,
11821
11948
  boundaryQuerySource,
11822
11949
  boundaryTableSource,
11950
+ buildAuthHeaders,
11823
11951
  buildBinaryFeatureFilter,
11824
11952
  buildPublicMapUrl,
11825
11953
  buildStatsUrl,
@@ -11838,6 +11966,7 @@ function hashBuckets(initialCount) {
11838
11966
  filterFunctions,
11839
11967
  geojsonFeatures,
11840
11968
  getApplicableFilters,
11969
+ getAuthCredentials,
11841
11970
  getClient,
11842
11971
  getColorAccessor,
11843
11972
  getColumnNameFromGeoColumn,
@@ -11847,6 +11976,7 @@ function hashBuckets(initialCount) {
11847
11976
  getIconUrlAccessor,
11848
11977
  getLayerDescriptor,
11849
11978
  getLayerProps,
11979
+ getLineStyleAccessor,
11850
11980
  getMaxMarkerSize,
11851
11981
  getSizeAccessor,
11852
11982
  getSorter,
@@ -11871,6 +12001,7 @@ function hashBuckets(initialCount) {
11871
12001
  rasterSource,
11872
12002
  removeFilter,
11873
12003
  requestWithParameters,
12004
+ rewriteUrlForSessionMode,
11874
12005
  scaleAggregationResLevel,
11875
12006
  scatterPlot,
11876
12007
  setClient,