@blokjs/shared 0.2.2 → 0.6.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.
@@ -1,55 +1,288 @@
1
1
  import _ from "lodash";
2
+ import { MapperResolutionError } from "./MapperResolutionError";
3
+ // =============================================================================
4
+ // Internal sentinels + helpers
5
+ // =============================================================================
6
+ /**
7
+ * Returned by the template-resolution path to signal "this placeholder
8
+ * could not be resolved; leave the literal `${...}` in place". Using a
9
+ * Symbol avoids ambiguity with the legitimate `undefined` value an
10
+ * expression might produce.
11
+ */
12
+ const TEMPLATE_RESOLUTION_FAILED = Symbol("TEMPLATE_RESOLUTION_FAILED");
13
+ function readMode() {
14
+ const raw = process.env.BLOK_MAPPER_MODE;
15
+ if (raw === "strict")
16
+ return "strict";
17
+ if (raw === "silent")
18
+ return "silent";
19
+ return "warn";
20
+ }
21
+ function readStepContext(ctx) {
22
+ const ctxAny = ctx;
23
+ const stepInfo = ctxAny._stepInfo;
24
+ const stepName = typeof stepInfo?.name === "string" ? stepInfo.name : undefined;
25
+ const workflowName = typeof ctx.workflow_name === "string" ? ctx.workflow_name : undefined;
26
+ return { workflowName, stepName };
27
+ }
28
+ /**
29
+ * Build the actionable error message — every line carries information
30
+ * a developer can act on: WHERE it failed, WHAT failed, WHY it likely
31
+ * failed, and HOW to fix it.
32
+ */
33
+ function buildErrorMessage(opts) {
34
+ const wf = opts.workflowName ?? "<unknown workflow>";
35
+ const step = opts.stepName ?? "<unknown step>";
36
+ const literal = opts.syntax === "js" ? `js/${opts.expression}` : `\${${opts.expression}}`;
37
+ const causeMsg = opts.cause instanceof Error ? opts.cause.message : String(opts.cause);
38
+ const hint = guessHint(opts.expression, causeMsg);
39
+ const lines = [
40
+ `[blok][mapper] Failed to resolve \`${literal}\` in step "${step}" of workflow "${wf}"`,
41
+ ` underlying: ${causeMsg}`,
42
+ ];
43
+ if (hint)
44
+ lines.push(` hint: ${hint}`);
45
+ lines.push(" fix: verify the referenced ctx path exists at run time. Set BLOK_MAPPER_MODE=strict in production to fail fast on these errors.");
46
+ return lines.join("\n");
47
+ }
48
+ /**
49
+ * Heuristic — translate common JS evaluation errors into actionable
50
+ * developer hints. Returns `null` when the error doesn't match any
51
+ * known pattern (the underlying message is still surfaced).
52
+ */
53
+ function guessHint(expression, errorMessage) {
54
+ // Most common case — `Cannot read properties of undefined (reading 'X')`
55
+ // or the older `Cannot read property 'X' of undefined`. Both forms
56
+ // appear depending on Node/Bun version.
57
+ const undefMatch = errorMessage.match(/Cannot read propert(?:y '(\w+)' of undefined|ies of undefined \(reading '(\w+)'\))/);
58
+ if (undefMatch) {
59
+ const prop = undefMatch[1] ?? undefMatch[2];
60
+ const segments = expression.split(".");
61
+ const parent = segments.slice(0, -1).join(".") || expression;
62
+ return `the path \`${parent}\` is undefined or doesn't have a "${prop}" field at run time. Check the trigger payload (ctx.req.body) or the upstream step's output (ctx.state.<id>).`;
63
+ }
64
+ // Identifier not in scope — only `ctx`, `data`, `func`, `vars` are
65
+ // available inside expressions.
66
+ const refMatch = errorMessage.match(/(\w+) is not defined/);
67
+ if (refMatch) {
68
+ return `\`${refMatch[1]}\` is not in scope. Available identifiers inside expressions: ctx, data, func, vars.`;
69
+ }
70
+ // Syntax error.
71
+ if (/SyntaxError/.test(errorMessage) || /Unexpected token/.test(errorMessage)) {
72
+ return "the expression is not valid JavaScript. Check for typos, unmatched parentheses, or stray characters.";
73
+ }
74
+ return null;
75
+ }
76
+ /**
77
+ * Route a warn-mode log line to the best available sink. Prefers
78
+ * `ctx.logger.logLevel("warn", ...)` so the warning lands in BOTH the
79
+ * console (via DefaultLogger) AND Studio's log viewer (via
80
+ * TracingLogger.normalizeLevel → addLog). Falls back to console.warn
81
+ * when no logger is attached (early-boot or hand-rolled test ctx).
82
+ */
83
+ function logViaCtxOrConsole(ctx, message) {
84
+ const logger = ctx.logger;
85
+ if (logger?.logLevel) {
86
+ try {
87
+ logger.logLevel("warn", message);
88
+ return;
89
+ }
90
+ catch {
91
+ // fall through to console.warn — never let logging itself crash a step.
92
+ }
93
+ }
94
+ if (logger?.log) {
95
+ try {
96
+ logger.log(message);
97
+ return;
98
+ }
99
+ catch {
100
+ // fall through
101
+ }
102
+ }
103
+ console.warn(message);
104
+ }
105
+ /**
106
+ * Coerce a resolved value to its string form for `${...}` interpolation.
107
+ *
108
+ * Pre-v0.3.x used `value as string` which fell back to `String(value)`
109
+ * via implicit coercion — producing `"[object Object]"` for any object/
110
+ * array. Now JSON-encodes complex values so interpolated strings
111
+ * preserve information instead of silently miscompiling.
112
+ *
113
+ * - `null` / `undefined` → empty string (matches user intent for
114
+ * missing optional fields)
115
+ * - `string` → identity
116
+ * - `number` / `boolean` / `bigint` → `String(value)`
117
+ * - everything else → `JSON.stringify(value)` with a defensive fallback
118
+ * to `String(value)` for circular structures.
119
+ */
120
+ function toInterpolatedString(value) {
121
+ if (value === null || value === undefined)
122
+ return "";
123
+ if (typeof value === "string")
124
+ return value;
125
+ if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
126
+ return String(value);
127
+ }
128
+ try {
129
+ return JSON.stringify(value) ?? String(value);
130
+ }
131
+ catch {
132
+ // JSON.stringify throws on circular references — degrade gracefully.
133
+ return String(value);
134
+ }
135
+ }
136
+ // =============================================================================
137
+ // Mapper
138
+ // =============================================================================
2
139
  class Mapper {
140
+ /**
141
+ * Walk an object recursively, resolving every string value via
142
+ * `replaceString`. Mutates in place. Used by `NodeBase.process` to
143
+ * resolve a step's `inputs` against the live `ctx` before the
144
+ * step runs.
145
+ *
146
+ * Object/array values are recursed into; primitive non-string
147
+ * values are left untouched. Null values are NOT recursed (avoids
148
+ * a TypeError on `for (const k in null)`).
149
+ */
3
150
  replaceObjectStrings(obj, ctx, data) {
4
151
  for (const key in obj) {
5
152
  if (Object.prototype.hasOwnProperty.call(obj, key)) {
6
153
  const value = obj[key];
7
154
  if (typeof value === "string") {
155
+ // `ParamsDictionary[key]` is typed `string`, but the
156
+ // runtime contract has always been "the resolved value
157
+ // keeps its actual type" (so `js/ctx.req.body.count`
158
+ // produces a number, not the string "42"). The
159
+ // `as unknown as string` boundary cast acknowledges
160
+ // that the type system can't express this widening
161
+ // without changing the global ParamsDictionary shape
162
+ // (a much larger refactor).
8
163
  obj[key] = this.replaceString(value, ctx, data);
9
164
  }
10
- else if (typeof value === "object") {
165
+ else if (value !== null && typeof value === "object") {
11
166
  this.replaceObjectStrings(value, ctx, data);
12
167
  }
13
168
  }
14
169
  }
15
170
  }
171
+ /**
172
+ * Resolve a single string. Returns `unknown` because a `js/...`
173
+ * expression may yield any value (number, object, array, etc.) —
174
+ * type fidelity is preserved across the resolver boundary.
175
+ *
176
+ * Pre-v0.3.x return was typed as `string` via `as string` cast
177
+ * which was a type lie; downstream consumers received the actual
178
+ * runtime value but couldn't see it through the type system.
179
+ */
16
180
  replaceString = (strData, ctx, data) => {
17
181
  let str = strData;
18
- // if (str.length > 15000) {
19
- // throw new Error("Input too long");
20
- // }
182
+ // === 1. `${path}` template interpolation ===
21
183
  const regex = /\${(.*?)}/g;
22
184
  const matches = str.match(regex);
23
185
  if (matches) {
24
186
  for (const match of matches) {
25
- try {
26
- const key = match.replace(/\${/g, "").replace(/}/g, "");
27
- const value = _.get(data, key) || this.runJs(key, ctx, data);
28
- // if (value) str = this.parseBasedOnType(str.replace(match, value), typeof value);
29
- str = str.replace(match, value);
30
- }
31
- catch (e) {
32
- console.log("Mapper Error 1", e);
187
+ const key = match.slice(2, -1); // strip `${` and `}`
188
+ const value = this.resolveTemplateExpression(key, ctx, data);
189
+ if (value !== TEMPLATE_RESOLUTION_FAILED) {
190
+ str = str.replace(match, toInterpolatedString(value));
33
191
  }
192
+ // On failure: leave the literal `${...}` placeholder in
193
+ // place. The failure was already reported per the active
194
+ // mode (warn/strict/silent).
34
195
  }
35
196
  }
36
- const result = this.jsMapper(str, ctx, data);
37
- return result;
197
+ // === 2. `js/...` full-string evaluation ===
198
+ return this.jsMapper(str, ctx, data);
38
199
  };
39
- runJs(str, ctx, data = {}, func = {}, vars = {}) {
40
- return Function("ctx", "data", "func", "vars", `"use strict";return (${str});`)(ctx, data, func, vars);
200
+ /**
201
+ * Resolve a `${path}` expression. Lodash lookup first; JS-eval
202
+ * fallback when the path is not in `data`. Returns the resolved
203
+ * value OR the failure sentinel.
204
+ */
205
+ resolveTemplateExpression(key, ctx, data) {
206
+ // Lodash lookup. Use explicit `=== undefined` instead of `||`
207
+ // so falsy-but-valid values (0, false, "", null) are preserved.
208
+ const lookupValue = _.get(data, key);
209
+ if (lookupValue !== undefined)
210
+ return lookupValue;
211
+ // Fallback to JS evaluation against ctx. Symmetric with jsMapper:
212
+ // pass `ctx.func` and `ctx.vars` so `${func.X}` and `${vars.X}`
213
+ // have the same scope as `js/func.X` / `js/vars.X`.
214
+ try {
215
+ return this.runJs(key, ctx, data, (ctx.func ?? {}), (ctx.vars ?? {}));
216
+ }
217
+ catch (cause) {
218
+ const stepCtx = readStepContext(ctx);
219
+ const error = new MapperResolutionError(buildErrorMessage({ expression: key, syntax: "template", ...stepCtx, cause }), { expression: key, syntax: "template", ...stepCtx, cause });
220
+ this.handleResolutionError(ctx, error);
221
+ return TEMPLATE_RESOLUTION_FAILED;
222
+ }
41
223
  }
224
+ /**
225
+ * Evaluate a `js/...` full-string expression. Returns whatever the
226
+ * expression produces (any type), or — in warn/silent mode on
227
+ * failure — the original literal `js/...` string.
228
+ *
229
+ * Strict-mode failures throw `MapperResolutionError`.
230
+ */
42
231
  jsMapper(str, ctx, data) {
232
+ if (typeof str !== "string" || !str.startsWith("js/"))
233
+ return str;
234
+ // `slice(3)` strips exactly the leading `js/` prefix.
235
+ // Pre-v0.3.x used `replace("js/", "")` which only strips the
236
+ // FIRST occurrence — fragile if the expression itself contained
237
+ // the substring `js/` (e.g., a URL like `https://js/foo`).
238
+ const expression = str.slice(3);
43
239
  try {
44
- if (typeof str === "string" && str.startsWith("js/")) {
45
- const fn = str.replace("js/", "");
46
- return this.runJs(fn, ctx, data, ctx.func, ctx.vars);
47
- }
240
+ return this.runJs(expression, ctx, data, (ctx.func ?? {}), (ctx.vars ?? {}));
48
241
  }
49
- catch (error) {
50
- console.log("Mapper Error 2", error);
242
+ catch (cause) {
243
+ const stepCtx = readStepContext(ctx);
244
+ const error = new MapperResolutionError(buildErrorMessage({ expression, syntax: "js", ...stepCtx, cause }), {
245
+ expression,
246
+ syntax: "js",
247
+ ...stepCtx,
248
+ cause,
249
+ });
250
+ this.handleResolutionError(ctx, error);
251
+ return str; // pre-v0.3.x behavior — pass through the literal string
51
252
  }
52
- return str;
253
+ }
254
+ /**
255
+ * Apply the configured mode (`BLOK_MAPPER_MODE`) to a resolution
256
+ * failure. In strict mode, the error escapes here and propagates
257
+ * up through `replaceString` → `NodeBase.blueprintMapper` →
258
+ * `NodeBase.process` → step error envelope.
259
+ */
260
+ handleResolutionError(ctx, error) {
261
+ const mode = readMode();
262
+ if (mode === "strict")
263
+ throw error;
264
+ if (mode === "silent")
265
+ return;
266
+ // mode === "warn"
267
+ logViaCtxOrConsole(ctx, error.message);
268
+ }
269
+ /**
270
+ * Sandboxed JS evaluation. Compiles the expression as a function
271
+ * body returning the expression value; binds `ctx`, `data`, `func`,
272
+ * `vars` as positional arguments; runs in `"use strict"` mode.
273
+ *
274
+ * Throws on any evaluation error (typo, undefined access, syntax,
275
+ * unknown identifier). Callers wrap in try/catch and translate to
276
+ * `MapperResolutionError`.
277
+ *
278
+ * Public via the prototype but documented as internal — the only
279
+ * supported call sites are inside this class.
280
+ */
281
+ runJs(str, ctx, data = {}, func = {}, vars = {}) {
282
+ // Function constructor (NOT eval) — creates a fresh function
283
+ // scope without lexical access to the surrounding module. Same
284
+ // security profile as the v1 implementation.
285
+ return Function("ctx", "data", "func", "vars", `"use strict";return (${str});`)(ctx, data, func, vars);
53
286
  }
54
287
  }
55
288
  export default new Mapper();
@@ -1 +1 @@
1
- {"version":3,"file":"Mapper.js","sourceRoot":"","sources":["../../src/utils/Mapper.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Mapper.js","sourceRoot":"","sources":["../../src/utils/Mapper.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Structured error thrown by `Mapper` when a workflow input expression
3
+ * cannot be resolved against the live `Context`.
4
+ *
5
+ * The Mapper resolves two template syntaxes inside step `inputs`:
6
+ * - **`${path.to.value}`** — interpolated string (lodash-path lookup
7
+ * with a JS-eval fallback)
8
+ * - **`"js/..."`** — full-string JS evaluation against `ctx`
9
+ *
10
+ * When evaluation throws (typo, undefined access, syntax error,
11
+ * unknown identifier), the Mapper packages the failure in a
12
+ * `MapperResolutionError` carrying full diagnostic context — the
13
+ * literal expression, which syntax it was, the workflow + step name,
14
+ * and the original underlying error as `cause`.
15
+ *
16
+ * **What happens next depends on `BLOK_MAPPER_MODE`** (read from env):
17
+ *
18
+ * - `"warn"` (default) — the error is caught inside the Mapper, logged
19
+ * via `ctx.logger.logLevel("warn", ...)` (which routes to both the
20
+ * console AND Studio's log viewer via `TracingLogger`), and the
21
+ * original expression string passes through to the node. Backward-
22
+ * compatible with v1 behavior + actionable diagnostics.
23
+ *
24
+ * - `"strict"` — the error escapes the Mapper, is re-thrown by
25
+ * `NodeBase.blueprintMapper`, and the step fails fast with a
26
+ * structured error. **Recommended for production deployments** —
27
+ * silent input resolution failures are a source of subtle bugs
28
+ * (the node receives a literal `"js/ctx.bad.path"` string instead
29
+ * of the resolved value, then produces wrong output downstream).
30
+ *
31
+ * - `"silent"` — pre-v0.3.x behavior: completely suppress the error
32
+ * (no log, no throw). Provided as an opt-out for tests / workflows
33
+ * that intentionally use undefined-tolerant resolution for optional
34
+ * fields. Discouraged.
35
+ *
36
+ * This class is a `core/shared` concern (not `core/runner`) because
37
+ * the Mapper itself lives in shared. Consumers in any package may
38
+ * `instanceof` check it to handle resolution failures specifically
39
+ * (e.g., a custom trigger may want to translate it into a 400-class
40
+ * HTTP response).
41
+ */
42
+ export declare class MapperResolutionError extends Error {
43
+ /** Always the literal string `"MapperResolutionError"`. */
44
+ readonly name = "MapperResolutionError";
45
+ /** Structured diagnostic context attached at construction time. */
46
+ readonly context: {
47
+ /**
48
+ * The literal expression that failed, WITHOUT the surrounding
49
+ * syntax markers. For `js/ctx.bad.path` the value is
50
+ * `"ctx.bad.path"`; for `${ctx.user.name}` it is `"ctx.user.name"`.
51
+ */
52
+ readonly expression: string;
53
+ /**
54
+ * Which template syntax was being parsed.
55
+ * - `"js"` — full-string `"js/..."` expression
56
+ * - `"template"` — interpolated `${...}` placeholder
57
+ */
58
+ readonly syntax: "js" | "template";
59
+ /**
60
+ * The workflow's `name:` field, when known. Read from
61
+ * `ctx.workflow_name`. Absent on hand-rolled test contexts.
62
+ */
63
+ readonly workflowName?: string;
64
+ /**
65
+ * The step's `id` (or v1 `name`), when known. Read from
66
+ * `ctx._stepInfo.name` which is set by `RunnerSteps` before
67
+ * each step runs. Absent during early-boot or test contexts.
68
+ */
69
+ readonly stepName?: string;
70
+ /**
71
+ * The original error thrown by the JS evaluator (typically a
72
+ * `TypeError` or `ReferenceError`). Preserved for full stack
73
+ * trace + downstream `instanceof` checks.
74
+ */
75
+ readonly cause?: unknown;
76
+ };
77
+ constructor(message: string, context: {
78
+ readonly expression: string;
79
+ readonly syntax: "js" | "template";
80
+ readonly workflowName?: string;
81
+ readonly stepName?: string;
82
+ readonly cause?: unknown;
83
+ });
84
+ }
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Structured error thrown by `Mapper` when a workflow input expression
3
+ * cannot be resolved against the live `Context`.
4
+ *
5
+ * The Mapper resolves two template syntaxes inside step `inputs`:
6
+ * - **`${path.to.value}`** — interpolated string (lodash-path lookup
7
+ * with a JS-eval fallback)
8
+ * - **`"js/..."`** — full-string JS evaluation against `ctx`
9
+ *
10
+ * When evaluation throws (typo, undefined access, syntax error,
11
+ * unknown identifier), the Mapper packages the failure in a
12
+ * `MapperResolutionError` carrying full diagnostic context — the
13
+ * literal expression, which syntax it was, the workflow + step name,
14
+ * and the original underlying error as `cause`.
15
+ *
16
+ * **What happens next depends on `BLOK_MAPPER_MODE`** (read from env):
17
+ *
18
+ * - `"warn"` (default) — the error is caught inside the Mapper, logged
19
+ * via `ctx.logger.logLevel("warn", ...)` (which routes to both the
20
+ * console AND Studio's log viewer via `TracingLogger`), and the
21
+ * original expression string passes through to the node. Backward-
22
+ * compatible with v1 behavior + actionable diagnostics.
23
+ *
24
+ * - `"strict"` — the error escapes the Mapper, is re-thrown by
25
+ * `NodeBase.blueprintMapper`, and the step fails fast with a
26
+ * structured error. **Recommended for production deployments** —
27
+ * silent input resolution failures are a source of subtle bugs
28
+ * (the node receives a literal `"js/ctx.bad.path"` string instead
29
+ * of the resolved value, then produces wrong output downstream).
30
+ *
31
+ * - `"silent"` — pre-v0.3.x behavior: completely suppress the error
32
+ * (no log, no throw). Provided as an opt-out for tests / workflows
33
+ * that intentionally use undefined-tolerant resolution for optional
34
+ * fields. Discouraged.
35
+ *
36
+ * This class is a `core/shared` concern (not `core/runner`) because
37
+ * the Mapper itself lives in shared. Consumers in any package may
38
+ * `instanceof` check it to handle resolution failures specifically
39
+ * (e.g., a custom trigger may want to translate it into a 400-class
40
+ * HTTP response).
41
+ */
42
+ export class MapperResolutionError extends Error {
43
+ /** Always the literal string `"MapperResolutionError"`. */
44
+ name = "MapperResolutionError";
45
+ /** Structured diagnostic context attached at construction time. */
46
+ context;
47
+ constructor(message, context) {
48
+ super(message);
49
+ this.context = context;
50
+ // Preserve the prototype chain across Babel/TS down-compilation —
51
+ // without this, `instanceof MapperResolutionError` fails on
52
+ // constructors transpiled to ES5 targets.
53
+ Object.setPrototypeOf(this, MapperResolutionError.prototype);
54
+ // Standard `Error.cause` mirror (Node 16.9+, ES2022). Lets
55
+ // `console.error(e)` pretty-print the underlying cause too.
56
+ if (context.cause !== undefined) {
57
+ this.cause = context.cause;
58
+ }
59
+ }
60
+ }
61
+ //# sourceMappingURL=MapperResolutionError.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MapperResolutionError.js","sourceRoot":"","sources":["../../src/utils/MapperResolutionError.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,MAAM,OAAO,qBAAsB,SAAQ,KAAK;IAC/C,2DAA2D;IAClC,IAAI,GAAG,uBAAuB,CAAC;IAExD,mEAAmE;IACnD,OAAO,CA8BrB;IAEF,YACC,OAAe,EACf,OAMC;QAED,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,kEAAkE;QAClE,4DAA4D;QAC5D,0CAA0C;QAC1C,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,qBAAqB,CAAC,SAAS,CAAC,CAAC;QAC7D,2DAA2D;QAC3D,4DAA4D;QAC5D,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;YAChC,IAAoC,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAC7D,CAAC;IACF,CAAC;CACD"}
@@ -1,5 +1,6 @@
1
1
  export { default as CpuUsage } from "./CpuUsage";
2
- export { default as Mapper } from "./Mapper";
2
+ export { default as Mapper, type MapperMode } from "./Mapper";
3
+ export { MapperResolutionError } from "./MapperResolutionError";
3
4
  export { default as MemoryUsage } from "./MemoryUsage";
4
5
  export { default as Metrics } from "./MetricsBase";
5
6
  export { default as Time } from "./Time";
@@ -1,5 +1,6 @@
1
1
  export { default as CpuUsage } from "./CpuUsage";
2
2
  export { default as Mapper } from "./Mapper";
3
+ export { MapperResolutionError } from "./MapperResolutionError";
3
4
  export { default as MemoryUsage } from "./MemoryUsage";
4
5
  export { default as Metrics } from "./MetricsBase";
5
6
  export { default as Time } from "./Time";
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,QAAQ,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAE,OAAO,IAAI,MAAM,EAAmB,MAAM,UAAU,CAAC;AAC9D,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,QAAQ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blokjs/shared",
3
- "version": "0.2.2",
3
+ "version": "0.6.0",
4
4
  "description": "Shared class, interfaces and types",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",