@callcium/sdk 0.1.0 → 0.3.0

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/dist/index.js CHANGED
@@ -20,19 +20,27 @@ var CallciumError = class CallciumError extends Error {
20
20
  * Thrown by `PolicyEnforcer.enforce` when calldata fails policy enforcement.
21
21
  * Distinct from `CallciumError("VALIDATION_ERROR")`, which signals static
22
22
  * issues in the policy itself.
23
- * Carries the full list of violations (one per failed group).
23
+ *
24
+ * Carries the full list of structured violations (one per failed group). The
25
+ * `Error.message` is a minimal non-lossy diagnostic summary built from the
26
+ * first violation's structured fields — not a presentation contract. Consumers
27
+ * rendering violations to users should iterate `violations` directly.
24
28
  */
25
29
  var PolicyViolationError = class PolicyViolationError extends Error {
26
30
  violations;
27
31
  constructor(violations) {
28
- const first = violations[0];
29
- const msg = first ? `Policy violation: ${first.message}` : "Policy violation";
30
- super(msg);
32
+ super(formatDiagnostic(violations[0]));
31
33
  this.name = "PolicyViolationError";
32
34
  this.violations = violations;
33
35
  Object.setPrototypeOf(this, PolicyViolationError.prototype);
34
36
  }
35
37
  };
38
+ /** Build a stack-trace-friendly diagnostic line from a violation's code and coordinates. */
39
+ function formatDiagnostic(violation) {
40
+ if (!violation) return "Policy violation";
41
+ const location = "group" in violation ? ` at group ${violation.group} rule ${violation.rule}` : "";
42
+ return `Policy violation: ${violation.code}${location}`;
43
+ }
36
44
  //#endregion
37
45
  //#region src/bytes.ts
38
46
  /** Regex that matches a valid hex body (even number of hex chars). */
@@ -1404,6 +1412,35 @@ function toBigInt(bytes, offset = 0) {
1404
1412
  function isSigned(typeCode) {
1405
1413
  return typeCode >= TypeCode.INT_MIN && typeCode <= TypeCode.INT_MAX;
1406
1414
  }
1415
+ /**
1416
+ * Canonicalize a raw 256-bit calldata word to its ABI value for the declared type (Policy Spec §7.8).
1417
+ * A scalar loaded from untrusted calldata may carry bits outside the declared width; masking
1418
+ * unsigned/address/bool/function/bytesN to width and sign-extending signed integers makes the
1419
+ * comparison use the canonical ABI value rather than the raw bytes.
1420
+ * @param value - The raw 256-bit word loaded from calldata.
1421
+ * @param typeCode - The declared type code of the value.
1422
+ * @returns The canonicalized 256-bit value.
1423
+ */
1424
+ function canonicalize(value, typeCode) {
1425
+ if (typeCode <= TypeCode.UINT_MAX) {
1426
+ const bits = BigInt((typeCode + 1) * 8);
1427
+ return bits === 256n ? value : value & (1n << bits) - 1n;
1428
+ }
1429
+ if (typeCode <= TypeCode.INT_MAX) {
1430
+ const bits = (typeCode - TypeCode.INT_MIN + 1) * 8;
1431
+ return bits === 256 ? value : BigInt.asUintN(256, BigInt.asIntN(bits, value));
1432
+ }
1433
+ if (typeCode === TypeCode.ADDRESS) return value & (1n << 160n) - 1n;
1434
+ if (typeCode === TypeCode.BOOL) return value & 1n;
1435
+ if (typeCode === TypeCode.FUNCTION) return value >> 64n << 64n;
1436
+ if (typeCode >= TypeCode.FIXED_BYTES_MIN && typeCode <= TypeCode.FIXED_BYTES_MAX) {
1437
+ const n = typeCode - TypeCode.FIXED_BYTES_MIN + 1;
1438
+ if (n === 32) return value;
1439
+ const padBits = BigInt((32 - n) * 8);
1440
+ return value >> padBits << padBits;
1441
+ }
1442
+ return value;
1443
+ }
1407
1444
  /** Return true when the operator code (with or without NOT flag) is a LENGTH_* variant. */
1408
1445
  function isLengthOp(opCode) {
1409
1446
  const base = opCode & ~Op.NOT;
@@ -2707,11 +2744,11 @@ function locate(tree, callData, pathBytes, baseOffset) {
2707
2744
  for (let i = 0; i < paramIndex; i++) head += headContribution(tree[i]);
2708
2745
  let base = baseOffset;
2709
2746
  let node = tree[paramIndex];
2710
- for (let s = 1; s < stepCount; s++) {
2711
- const step = readStep(pathBytes, s);
2747
+ for (let stepIndex = 1; stepIndex < stepCount; stepIndex++) {
2748
+ const step = readStep(pathBytes, stepIndex);
2712
2749
  if (isQuantifier(step)) {
2713
- const remaining = pathBytes.subarray((s + 1) * 2);
2714
- for (let r = 0; r < remaining.length / 2; r++) if (isQuantifier(readStep(remaining, r))) throw new CallciumError("INVALID_QUANTIFIER", "Nested quantifiers are not supported.");
2750
+ const remaining = pathBytes.subarray((stepIndex + 1) * 2);
2751
+ for (let remainingStepIndex = 0; remainingStepIndex < remaining.length / 2; remainingStepIndex++) if (isQuantifier(readStep(remaining, remainingStepIndex))) throw new CallciumError("INVALID_QUANTIFIER", "Nested quantifiers are not supported.");
2715
2752
  return {
2716
2753
  ok: true,
2717
2754
  type: "quantifier",
@@ -2887,8 +2924,8 @@ function loadSlice(callData, location) {
2887
2924
  function descendPath(callData, location, pathBytes) {
2888
2925
  const stepCount = pathBytes.length / 2;
2889
2926
  let { head, base, node } = location;
2890
- for (let s = 0; s < stepCount; s++) {
2891
- const step = readStep(pathBytes, s);
2927
+ for (let stepIndex = 0; stepIndex < stepCount; stepIndex++) {
2928
+ const step = readStep(pathBytes, stepIndex);
2892
2929
  const result = descend(node, callData, head, base, step);
2893
2930
  if (result.type === "violation") return {
2894
2931
  ok: false,
@@ -2916,38 +2953,27 @@ function addressToBigInt(hex) {
2916
2953
  padded.set(bytes, 32 - bytes.length);
2917
2954
  return toBigInt(padded, 0);
2918
2955
  }
2919
- /** Format a bigint as a compact hex string without leading-zero padding. */
2920
- function compactHex(value) {
2921
- if (value === 0n) return "0x0";
2922
- return `0x${value.toString(16)}`;
2923
- }
2924
- /** Truncate a hex string to at most maxChars characters, adding ellipsis if needed. */
2925
- function truncateHexForMessage(hex, maxChars = 66) {
2926
- if (hex.length <= maxChars) return hex;
2927
- return `${hex.slice(0, maxChars - 1)}…`;
2928
- }
2929
- /** Format a decoded operand as decimal for length ops, otherwise compact hex. */
2930
- function formatOperandValue(value, opCode) {
2931
- return isLengthOp(opCode) ? value.toString(10) : compactHex(value);
2932
- }
2933
- /** Format the constraint (operator + operands) from a single lookupOp call. */
2934
- function formatConstraint(opCode, operandData) {
2935
- const negated = (opCode & Op.NOT) !== 0;
2936
- const { label, operands } = lookupOp(opCode);
2937
- const op = negated ? `not ${label}` : label;
2938
- let formattedOperands;
2939
- if (operands === "variadic") formattedOperands = `(${operandData.length / 32} values)`;
2940
- else if (operands === "range") {
2941
- const min = toBigInt(operandData, 0);
2942
- const max = toBigInt(operandData, 32);
2943
- formattedOperands = `[${formatOperandValue(min, opCode)}, ${formatOperandValue(max, opCode)}]`;
2944
- } else formattedOperands = formatOperandValue(toBigInt(operandData, 0), opCode);
2945
- return `${op} ${formattedOperands}`;
2946
- }
2947
- /** Build a self-contained VALUE_MISMATCH message for a scalar or length comparison. */
2948
- function mismatchMessage(opCode, actual, operandData) {
2949
- const display = typeof actual === "number" ? String(actual) : truncateHexForMessage(compactHex(actual));
2950
- return `constraint ${formatConstraint(opCode, operandData)} violated by ${display}`;
2956
+ /**
2957
+ * Walk a descriptor subtree through path steps and return the terminal leaf type code.
2958
+ *
2959
+ * Used only for violation metadata. Valid policies have structurally valid
2960
+ * quantifier suffixes (enforced by `PolicyValidator`); if a hand-crafted blob
2961
+ * violates that invariant, return the last resolvable node's type code as
2962
+ * best-effort diagnostic context.
2963
+ */
2964
+ function resolveLeafTypeCode(elementNode, remainingPath) {
2965
+ let node = elementNode;
2966
+ const stepCount = remainingPath.length / 2;
2967
+ for (let step = 0; step < stepCount; step++) {
2968
+ const childIndex = readU16(remainingPath, step * 2);
2969
+ if (node.type === "tuple") {
2970
+ const field = node.fields[childIndex];
2971
+ if (!field) break;
2972
+ node = field;
2973
+ } else if (node.type === "staticArray" || node.type === "dynamicArray") node = node.element;
2974
+ else break;
2975
+ }
2976
+ return node.typeCode;
2951
2977
  }
2952
2978
  /**
2953
2979
  * Check a policy against ABI-encoded call data without throwing on violations.
@@ -2963,10 +2989,7 @@ function check(policy, callData, context) {
2963
2989
  if (!decoded.isSelectorless) {
2964
2990
  if (callDataBytes.length < 4) return {
2965
2991
  ok: false,
2966
- violations: [{
2967
- code: "MISSING_SELECTOR",
2968
- message: "Calldata too short to contain a selector"
2969
- }]
2992
+ violations: [{ code: "MISSING_SELECTOR" }]
2970
2993
  };
2971
2994
  const expectedSelector = decoded.selector.value;
2972
2995
  const actualSelector = bytesToHex(callDataBytes.subarray(0, 4));
@@ -2974,8 +2997,8 @@ function check(policy, callData, context) {
2974
2997
  ok: false,
2975
2998
  violations: [{
2976
2999
  code: "SELECTOR_MISMATCH",
2977
- message: `Expected selector ${expectedSelector}, got ${actualSelector}`,
2978
- resolvedValue: actualSelector
3000
+ resolvedValue: actualSelector,
3001
+ expectedValue: expectedSelector
2979
3002
  }]
2980
3003
  };
2981
3004
  }
@@ -3028,8 +3051,10 @@ function evaluateRule(rule, tree, callDataBytes, baseOffset, groupIndex, ruleInd
3028
3051
  group: groupIndex,
3029
3052
  rule: ruleIndex,
3030
3053
  code: locResult.code,
3031
- message: `Navigation failed: ${locResult.code}`,
3032
- path: rule.path.value
3054
+ scope: Scope.CALLDATA,
3055
+ path: rule.path.value,
3056
+ opCode,
3057
+ operandData: rule.data.value
3033
3058
  };
3034
3059
  if (locResult.type === "quantifier") return evaluateQuantifier(locResult.quantifier, callDataBytes, opCode, operandData, groupIndex, ruleIndex, rule.path.value);
3035
3060
  return evaluateLeaf(locResult.location, callDataBytes, opCode, operandData, groupIndex, ruleIndex, rule.path.value);
@@ -3044,23 +3069,33 @@ function evaluateContextRule(pathBytes, opCode, operandData, groupIndex, ruleInd
3044
3069
  group: groupIndex,
3045
3070
  rule: ruleIndex,
3046
3071
  code: "MISSING_CONTEXT",
3047
- message: `Context property ${propInfo.label} not provided`,
3048
- path: pathHex
3072
+ scope: Scope.CONTEXT,
3073
+ path: pathHex,
3074
+ typeCode: propInfo.typeCode
3049
3075
  };
3050
3076
  let value;
3051
3077
  if (typeof contextValue === "string") value = addressToBigInt(contextValue);
3052
3078
  else value = contextValue;
3053
- if (!applyOperator(opCode, value, 32, operandData, TypeCode.UINT_MAX)) return {
3079
+ if (!applyOperator(opCode, value, 32, operandData, propInfo.typeCode)) return {
3054
3080
  group: groupIndex,
3055
3081
  rule: ruleIndex,
3056
3082
  code: "VALUE_MISMATCH",
3057
- message: mismatchMessage(opCode, value, operandData),
3083
+ scope: Scope.CONTEXT,
3058
3084
  path: pathHex,
3085
+ opCode,
3086
+ operandData: bytesToHex(operandData),
3087
+ typeCode: propInfo.typeCode,
3059
3088
  resolvedValue: bigintToHex(value)
3060
3089
  };
3061
3090
  return null;
3062
3091
  }
3063
- /** Load a value from calldata at the given location and apply the operator. */
3092
+ /**
3093
+ * Load a value from calldata at the given location and apply the operator.
3094
+ *
3095
+ * `resolvedValue` is normalised at the decision point: length operators encode
3096
+ * the byte/element count as a hex bigint; scalar operators preserve the full
3097
+ * 32-byte ABI word so downstream rendering can decode left-aligned `bytesN` faithfully.
3098
+ */
3064
3099
  function applyLeafOperator(callDataBytes, location, opCode, operandData) {
3065
3100
  const { node } = location;
3066
3101
  if (isLengthOp(opCode)) {
@@ -3072,61 +3107,69 @@ function applyLeafOperator(callDataBytes, location, opCode, operandData) {
3072
3107
  } else valueLength = node.staticSize;
3073
3108
  return {
3074
3109
  passed: applyOperator(opCode, 0n, valueLength, operandData, node.typeCode),
3075
- length: valueLength
3110
+ resolvedValue: bigintToHex(BigInt(valueLength))
3076
3111
  };
3077
3112
  }
3078
3113
  const result = loadScalar(callDataBytes, location);
3079
3114
  if (!result.ok) return { error: result.code };
3080
- const value = toBigInt(result.value, 0);
3115
+ const value = canonicalize(toBigInt(result.value, 0), node.typeCode);
3081
3116
  return {
3082
3117
  passed: applyOperator(opCode, value, 32, operandData, node.typeCode),
3083
- value
3118
+ resolvedValue: bigintToHex(value)
3084
3119
  };
3085
3120
  }
3086
3121
  /** Evaluate a leaf rule, producing a violation on failure or null on pass. */
3087
3122
  function evaluateLeaf(location, callDataBytes, opCode, operandData, groupIndex, ruleIndex, pathHex) {
3088
3123
  const result = applyLeafOperator(callDataBytes, location, opCode, operandData);
3089
- if ("error" in result) {
3090
- const message = isLengthOp(opCode) ? `Failed to read length: ${result.error}` : `Failed to load value: ${result.error}`;
3091
- return {
3092
- group: groupIndex,
3093
- rule: ruleIndex,
3094
- code: result.error,
3095
- message,
3096
- path: pathHex
3097
- };
3098
- }
3099
- if (!result.passed) {
3100
- const actual = result.value !== void 0 ? result.value : result.length ?? 0;
3101
- return {
3102
- group: groupIndex,
3103
- rule: ruleIndex,
3104
- code: "VALUE_MISMATCH",
3105
- message: mismatchMessage(opCode, actual, operandData),
3106
- path: pathHex,
3107
- resolvedValue: bigintToHex(typeof actual === "number" ? BigInt(actual) : actual)
3108
- };
3109
- }
3124
+ const typeCode = location.node.typeCode;
3125
+ if ("error" in result) return {
3126
+ group: groupIndex,
3127
+ rule: ruleIndex,
3128
+ code: result.error,
3129
+ scope: Scope.CALLDATA,
3130
+ path: pathHex,
3131
+ opCode,
3132
+ operandData: bytesToHex(operandData),
3133
+ typeCode
3134
+ };
3135
+ if (!result.passed) return {
3136
+ group: groupIndex,
3137
+ rule: ruleIndex,
3138
+ code: "VALUE_MISMATCH",
3139
+ scope: Scope.CALLDATA,
3140
+ path: pathHex,
3141
+ opCode,
3142
+ operandData: bytesToHex(operandData),
3143
+ typeCode,
3144
+ resolvedValue: result.resolvedValue
3145
+ };
3110
3146
  return null;
3111
3147
  }
3112
3148
  /** Evaluate a quantified rule by iterating over array elements with ALL/ANY semantics. */
3113
3149
  function evaluateQuantifier(qResult, callDataBytes, opCode, operandData, groupIndex, ruleIndex, pathHex) {
3114
3150
  const { quantifier, location: arrayLocation, remainingPath } = qResult;
3151
+ const operandHex = bytesToHex(operandData);
3152
+ const arrayNode = arrayLocation.node;
3153
+ const leafTypeCode = resolveLeafTypeCode(arrayNode.type === "staticArray" || arrayNode.type === "dynamicArray" ? arrayNode.element : arrayNode, remainingPath);
3115
3154
  const shapeResult = arrayShape(callDataBytes, arrayLocation);
3116
3155
  if (!shapeResult.ok) return {
3117
3156
  group: groupIndex,
3118
3157
  rule: ruleIndex,
3119
3158
  code: shapeResult.code,
3120
- message: `Failed to read array shape: ${shapeResult.code}`,
3121
- path: pathHex
3159
+ scope: Scope.CALLDATA,
3160
+ path: pathHex,
3161
+ opCode,
3162
+ operandData: operandHex,
3163
+ typeCode: leafTypeCode
3122
3164
  };
3123
3165
  const shape = shapeResult.shape;
3124
3166
  if (shape.length > Limits.MAX_QUANTIFIED_ARRAY_LENGTH) return {
3125
3167
  group: groupIndex,
3126
3168
  rule: ruleIndex,
3127
3169
  code: "QUANTIFIER_LIMIT_EXCEEDED",
3128
- message: `Array length ${shape.length} exceeds maximum ${Limits.MAX_QUANTIFIED_ARRAY_LENGTH}`,
3129
- path: pathHex
3170
+ scope: Scope.CALLDATA,
3171
+ path: pathHex,
3172
+ resolvedValue: bigintToHex(BigInt(shape.length))
3130
3173
  };
3131
3174
  if (shape.length === 0) {
3132
3175
  if (quantifier === Quantifier.ALL_OR_EMPTY) return null;
@@ -3134,7 +3177,7 @@ function evaluateQuantifier(qResult, callDataBytes, opCode, operandData, groupIn
3134
3177
  group: groupIndex,
3135
3178
  rule: ruleIndex,
3136
3179
  code: "QUANTIFIER_EMPTY_ARRAY",
3137
- message: "Quantifier applied to empty array",
3180
+ scope: Scope.CALLDATA,
3138
3181
  path: pathHex
3139
3182
  };
3140
3183
  }
@@ -3147,70 +3190,82 @@ function evaluateQuantifier(qResult, callDataBytes, opCode, operandData, groupIn
3147
3190
  group: groupIndex,
3148
3191
  rule: ruleIndex,
3149
3192
  code: elemResult.code,
3150
- message: `Quantifier element ${elemIndex}: ${elemResult.code}`,
3151
- path: pathHex
3193
+ scope: Scope.CALLDATA,
3194
+ path: pathHex,
3195
+ opCode,
3196
+ operandData: operandHex,
3197
+ typeCode: leafTypeCode,
3198
+ elementIndex: elemIndex
3152
3199
  };
3153
3200
  continue;
3154
3201
  }
3155
3202
  const elemLocation = elemResult.location;
3156
- let elemPassed;
3203
+ let leafLocation;
3157
3204
  if (hasSuffix) {
3158
- const leafResult = descendPath(callDataBytes, elemLocation, remainingPath);
3159
- if (!leafResult.ok) {
3160
- if (isUniversal) return {
3161
- group: groupIndex,
3162
- rule: ruleIndex,
3163
- code: leafResult.code,
3164
- message: `Quantifier element ${elemIndex} navigation failed: ${leafResult.code}`,
3165
- path: pathHex
3166
- };
3167
- continue;
3168
- }
3169
- elemPassed = evaluateLeafValue(leafResult.location, callDataBytes, opCode, operandData);
3170
- } else {
3171
- const leafResult = applyLeafOperator(callDataBytes, elemLocation, opCode, operandData);
3172
- if ("error" in leafResult) {
3205
+ const navResult = descendPath(callDataBytes, elemLocation, remainingPath);
3206
+ if (!navResult.ok) {
3173
3207
  if (isUniversal) return {
3174
3208
  group: groupIndex,
3175
3209
  rule: ruleIndex,
3176
- code: leafResult.error,
3177
- message: `Quantifier element ${elemIndex}: ${leafResult.error}`,
3178
- path: pathHex
3210
+ code: navResult.code,
3211
+ scope: Scope.CALLDATA,
3212
+ path: pathHex,
3213
+ opCode,
3214
+ operandData: operandHex,
3215
+ typeCode: leafTypeCode,
3216
+ elementIndex: elemIndex
3179
3217
  };
3180
3218
  continue;
3181
3219
  }
3182
- elemPassed = leafResult.passed;
3220
+ leafLocation = navResult.location;
3221
+ } else leafLocation = elemLocation;
3222
+ const applied = applyLeafOperator(callDataBytes, leafLocation, opCode, operandData);
3223
+ if ("error" in applied) {
3224
+ if (isUniversal) return {
3225
+ group: groupIndex,
3226
+ rule: ruleIndex,
3227
+ code: applied.error,
3228
+ scope: Scope.CALLDATA,
3229
+ path: pathHex,
3230
+ opCode,
3231
+ operandData: operandHex,
3232
+ typeCode: leafTypeCode,
3233
+ elementIndex: elemIndex
3234
+ };
3235
+ continue;
3183
3236
  }
3184
- if (isUniversal && !elemPassed) return {
3237
+ if (isUniversal && !applied.passed) return {
3185
3238
  group: groupIndex,
3186
3239
  rule: ruleIndex,
3187
3240
  code: "VALUE_MISMATCH",
3188
- message: `constraint ${formatConstraint(opCode, operandData)} violated at element ${elemIndex}`,
3189
- path: pathHex
3241
+ scope: Scope.CALLDATA,
3242
+ path: pathHex,
3243
+ opCode,
3244
+ operandData: operandHex,
3245
+ typeCode: leafTypeCode,
3246
+ resolvedValue: applied.resolvedValue,
3247
+ elementIndex: elemIndex
3190
3248
  };
3191
- if (!isUniversal && elemPassed) return null;
3249
+ if (!isUniversal && applied.passed) return null;
3192
3250
  }
3193
3251
  if (isUniversal) return null;
3194
3252
  return {
3195
3253
  group: groupIndex,
3196
3254
  rule: ruleIndex,
3197
3255
  code: "VALUE_MISMATCH",
3198
- message: `constraint ${formatConstraint(opCode, operandData)} violated by all elements`,
3199
- path: pathHex
3256
+ scope: Scope.CALLDATA,
3257
+ path: pathHex,
3258
+ opCode,
3259
+ operandData: operandHex,
3260
+ typeCode: leafTypeCode
3200
3261
  };
3201
3262
  }
3202
- /** Apply a leaf operator and return a boolean. Returns false on calldata read failure. */
3203
- function evaluateLeafValue(location, callDataBytes, opCode, operandData) {
3204
- const result = applyLeafOperator(callDataBytes, location, opCode, operandData);
3205
- if ("error" in result) return false;
3206
- return result.passed;
3207
- }
3208
3263
  /** Check and enforce policies against ABI-encoded call data. */
3209
3264
  const PolicyEnforcer = {
3210
3265
  check,
3211
3266
  enforce
3212
3267
  };
3213
3268
  //#endregion
3214
- export { CallciumError, ContextProperty, Descriptor, DescriptorCoder, Limits, Op, PolicyBuilder, PolicyCoder, PolicyEnforcer, PolicyValidator, PolicyViolationError, Quantifier, Scope, TypeCode, arg, blockNumber, blockTimestamp, bytesToHex, chainId, hexToBytes, isOpAllowed, isQuantifier, lookupContextProperty, lookupOp, lookupQuantifier, lookupScope, lookupTypeCode, msgSender, msgValue, parsePathSteps, toAddress, txOrigin };
3269
+ export { CallciumError, ContextProperty, Descriptor, DescriptorCoder, Limits, Op, PolicyBuilder, PolicyCoder, PolicyEnforcer, PolicyValidator, PolicyViolationError, Quantifier, Scope, TypeCode, arg, blockNumber, blockTimestamp, bytesToHex, chainId, hexToBytes, isLengthOp, isOpAllowed, isQuantifier, lookupContextProperty, lookupOp, lookupQuantifier, lookupScope, lookupTypeCode, msgSender, msgValue, parsePathSteps, toAddress, txOrigin };
3215
3270
 
3216
3271
  //# sourceMappingURL=index.js.map