@guidelytech/shared 0.0.0-stage → 0.2.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/README.md +16 -2
- package/dist/chunk-OFBIZEM5.js +322 -0
- package/dist/chunk-OFBIZEM5.js.map +1 -0
- package/dist/index.cjs +1042 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +3356 -0
- package/dist/index.d.ts +3356 -0
- package/dist/index.js +669 -0
- package/dist/index.js.map +1 -0
- package/dist/runtime.cjs +369 -0
- package/dist/runtime.cjs.map +1 -0
- package/dist/runtime.d.cts +80 -0
- package/dist/runtime.d.ts +80 -0
- package/dist/runtime.js +49 -0
- package/dist/runtime.js.map +1 -0
- package/package.json +62 -3
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/** FNV-1a 32-bit hash; deterministic across SDK and server for rollout bucketing. */
|
|
2
|
+
declare function fnv1a(input: string): number;
|
|
3
|
+
/** Deterministic 0-99 bucket for percentage rollouts. */
|
|
4
|
+
declare function rolloutBucket(subject: string, salt: string): number;
|
|
5
|
+
declare function slugify(input: string): string;
|
|
6
|
+
/** URL-safe random id. Uses crypto when available, falls back to Math.random (ids are not secrets). */
|
|
7
|
+
declare function randomId(size?: number): string;
|
|
8
|
+
declare function isPlainObject(v: unknown): v is Record<string, unknown>;
|
|
9
|
+
/** Safe nested getter: get(obj, "account.plan") */
|
|
10
|
+
declare function getPath(obj: unknown, path: string): unknown;
|
|
11
|
+
declare function clamp(n: number, min: number, max: number): number;
|
|
12
|
+
/** Glob-style URL pattern match: `*` matches any chars except `/`, `**` matches anything. */
|
|
13
|
+
declare function matchUrlPattern(pattern: string, url: string): boolean;
|
|
14
|
+
declare function stripOrigin(url: string): string;
|
|
15
|
+
/** Safe regexp construction with a length cap to limit ReDoS exposure. */
|
|
16
|
+
declare function safeRegExp(source: string, flags?: string): RegExp | null;
|
|
17
|
+
|
|
18
|
+
declare const RULE_OPERATORS: readonly ["equals", "not_equals", "contains", "not_contains", "starts_with", "ends_with", "exists", "not_exists", "gt", "gte", "lt", "lte", "in", "not_in", "regex", "is_true", "is_false", "before", "after"];
|
|
19
|
+
type RuleOperator = (typeof RULE_OPERATORS)[number];
|
|
20
|
+
declare const RULE_FIELDS: readonly ["user.attribute", "account.attribute", "user.role", "user.plan", "url.path", "url.full", "url.query", "device.type", "device.browser", "device.os", "visitor.firstVisit", "visitor.returning", "event.seen", "guide.completed", "guide.dismissed", "guide.seen", "checklist.completed", "audience.member", "datetime.now", "datetime.dayOfWeek", "datetime.hour", "rollout.percentage", "environment", "locale"];
|
|
21
|
+
type RuleField = (typeof RULE_FIELDS)[number];
|
|
22
|
+
interface Rule {
|
|
23
|
+
id: string;
|
|
24
|
+
field: RuleField;
|
|
25
|
+
/** For attribute/query/event fields: the attribute key, query param name, event name, guide id... */
|
|
26
|
+
key?: string;
|
|
27
|
+
op: RuleOperator;
|
|
28
|
+
value?: string | number | boolean | string[];
|
|
29
|
+
/** When true, the rule is negated (exclusion rule). */
|
|
30
|
+
negate?: boolean;
|
|
31
|
+
}
|
|
32
|
+
type RuleGroup = {
|
|
33
|
+
id: string;
|
|
34
|
+
op: "and" | "or";
|
|
35
|
+
rules: Array<Rule | RuleGroup>;
|
|
36
|
+
negate?: boolean;
|
|
37
|
+
};
|
|
38
|
+
declare function isRuleGroup(r: Rule | RuleGroup): r is RuleGroup;
|
|
39
|
+
declare function emptyRuleGroup(id?: string): RuleGroup;
|
|
40
|
+
/** Everything targeting evaluation can see. Built by the SDK (browser) or the server. */
|
|
41
|
+
interface TargetingContext {
|
|
42
|
+
userId?: string | null;
|
|
43
|
+
anonymousId: string;
|
|
44
|
+
userAttributes: Record<string, unknown>;
|
|
45
|
+
accountAttributes: Record<string, unknown>;
|
|
46
|
+
url: string;
|
|
47
|
+
path: string;
|
|
48
|
+
query: Record<string, string>;
|
|
49
|
+
device: {
|
|
50
|
+
type: "desktop" | "tablet" | "mobile";
|
|
51
|
+
browser?: string;
|
|
52
|
+
os?: string;
|
|
53
|
+
};
|
|
54
|
+
firstVisit: boolean;
|
|
55
|
+
eventsSeen: Set<string> | string[];
|
|
56
|
+
completedGuides: Set<string> | string[];
|
|
57
|
+
dismissedGuides: Set<string> | string[];
|
|
58
|
+
seenGuides: Set<string> | string[];
|
|
59
|
+
completedChecklists: Set<string> | string[];
|
|
60
|
+
audienceIds: Set<string> | string[];
|
|
61
|
+
now: Date;
|
|
62
|
+
environment: string;
|
|
63
|
+
locale?: string;
|
|
64
|
+
/** Salt for rollout (guide id). Set per guide before evaluating. */
|
|
65
|
+
rolloutSalt?: string;
|
|
66
|
+
}
|
|
67
|
+
declare function compare(op: RuleOperator, actual: unknown, expected: Rule["value"]): boolean;
|
|
68
|
+
declare function evaluateRule(rule: Rule, ctx: TargetingContext): boolean;
|
|
69
|
+
/** Evaluate a rule tree. An empty group matches everyone. */
|
|
70
|
+
declare function evaluateRules(group: RuleGroup | null | undefined, ctx: TargetingContext): boolean;
|
|
71
|
+
/** Fields whose evaluation requires server-held data. Used by docs/UI to annotate rules. */
|
|
72
|
+
declare const SERVER_ASSISTED_FIELDS: RuleField[];
|
|
73
|
+
declare function describeRule(rule: Rule): string;
|
|
74
|
+
|
|
75
|
+
/** Reserved property names that are stripped from `properties` to avoid collecting sensitive data. */
|
|
76
|
+
declare const SENSITIVE_PROPERTY_PATTERN: RegExp;
|
|
77
|
+
declare const MAX_PROPERTY_BYTES: number;
|
|
78
|
+
declare function sanitizeProperties(props: Record<string, unknown> | undefined): Record<string, unknown>;
|
|
79
|
+
|
|
80
|
+
export { MAX_PROPERTY_BYTES, RULE_FIELDS, RULE_OPERATORS, type Rule, type RuleField, type RuleGroup, type RuleOperator, SENSITIVE_PROPERTY_PATTERN, SERVER_ASSISTED_FIELDS, type TargetingContext, clamp, compare, describeRule, emptyRuleGroup, evaluateRule, evaluateRules, fnv1a, getPath, isPlainObject, isRuleGroup, matchUrlPattern, randomId, rolloutBucket, safeRegExp, sanitizeProperties, slugify, stripOrigin };
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/** FNV-1a 32-bit hash; deterministic across SDK and server for rollout bucketing. */
|
|
2
|
+
declare function fnv1a(input: string): number;
|
|
3
|
+
/** Deterministic 0-99 bucket for percentage rollouts. */
|
|
4
|
+
declare function rolloutBucket(subject: string, salt: string): number;
|
|
5
|
+
declare function slugify(input: string): string;
|
|
6
|
+
/** URL-safe random id. Uses crypto when available, falls back to Math.random (ids are not secrets). */
|
|
7
|
+
declare function randomId(size?: number): string;
|
|
8
|
+
declare function isPlainObject(v: unknown): v is Record<string, unknown>;
|
|
9
|
+
/** Safe nested getter: get(obj, "account.plan") */
|
|
10
|
+
declare function getPath(obj: unknown, path: string): unknown;
|
|
11
|
+
declare function clamp(n: number, min: number, max: number): number;
|
|
12
|
+
/** Glob-style URL pattern match: `*` matches any chars except `/`, `**` matches anything. */
|
|
13
|
+
declare function matchUrlPattern(pattern: string, url: string): boolean;
|
|
14
|
+
declare function stripOrigin(url: string): string;
|
|
15
|
+
/** Safe regexp construction with a length cap to limit ReDoS exposure. */
|
|
16
|
+
declare function safeRegExp(source: string, flags?: string): RegExp | null;
|
|
17
|
+
|
|
18
|
+
declare const RULE_OPERATORS: readonly ["equals", "not_equals", "contains", "not_contains", "starts_with", "ends_with", "exists", "not_exists", "gt", "gte", "lt", "lte", "in", "not_in", "regex", "is_true", "is_false", "before", "after"];
|
|
19
|
+
type RuleOperator = (typeof RULE_OPERATORS)[number];
|
|
20
|
+
declare const RULE_FIELDS: readonly ["user.attribute", "account.attribute", "user.role", "user.plan", "url.path", "url.full", "url.query", "device.type", "device.browser", "device.os", "visitor.firstVisit", "visitor.returning", "event.seen", "guide.completed", "guide.dismissed", "guide.seen", "checklist.completed", "audience.member", "datetime.now", "datetime.dayOfWeek", "datetime.hour", "rollout.percentage", "environment", "locale"];
|
|
21
|
+
type RuleField = (typeof RULE_FIELDS)[number];
|
|
22
|
+
interface Rule {
|
|
23
|
+
id: string;
|
|
24
|
+
field: RuleField;
|
|
25
|
+
/** For attribute/query/event fields: the attribute key, query param name, event name, guide id... */
|
|
26
|
+
key?: string;
|
|
27
|
+
op: RuleOperator;
|
|
28
|
+
value?: string | number | boolean | string[];
|
|
29
|
+
/** When true, the rule is negated (exclusion rule). */
|
|
30
|
+
negate?: boolean;
|
|
31
|
+
}
|
|
32
|
+
type RuleGroup = {
|
|
33
|
+
id: string;
|
|
34
|
+
op: "and" | "or";
|
|
35
|
+
rules: Array<Rule | RuleGroup>;
|
|
36
|
+
negate?: boolean;
|
|
37
|
+
};
|
|
38
|
+
declare function isRuleGroup(r: Rule | RuleGroup): r is RuleGroup;
|
|
39
|
+
declare function emptyRuleGroup(id?: string): RuleGroup;
|
|
40
|
+
/** Everything targeting evaluation can see. Built by the SDK (browser) or the server. */
|
|
41
|
+
interface TargetingContext {
|
|
42
|
+
userId?: string | null;
|
|
43
|
+
anonymousId: string;
|
|
44
|
+
userAttributes: Record<string, unknown>;
|
|
45
|
+
accountAttributes: Record<string, unknown>;
|
|
46
|
+
url: string;
|
|
47
|
+
path: string;
|
|
48
|
+
query: Record<string, string>;
|
|
49
|
+
device: {
|
|
50
|
+
type: "desktop" | "tablet" | "mobile";
|
|
51
|
+
browser?: string;
|
|
52
|
+
os?: string;
|
|
53
|
+
};
|
|
54
|
+
firstVisit: boolean;
|
|
55
|
+
eventsSeen: Set<string> | string[];
|
|
56
|
+
completedGuides: Set<string> | string[];
|
|
57
|
+
dismissedGuides: Set<string> | string[];
|
|
58
|
+
seenGuides: Set<string> | string[];
|
|
59
|
+
completedChecklists: Set<string> | string[];
|
|
60
|
+
audienceIds: Set<string> | string[];
|
|
61
|
+
now: Date;
|
|
62
|
+
environment: string;
|
|
63
|
+
locale?: string;
|
|
64
|
+
/** Salt for rollout (guide id). Set per guide before evaluating. */
|
|
65
|
+
rolloutSalt?: string;
|
|
66
|
+
}
|
|
67
|
+
declare function compare(op: RuleOperator, actual: unknown, expected: Rule["value"]): boolean;
|
|
68
|
+
declare function evaluateRule(rule: Rule, ctx: TargetingContext): boolean;
|
|
69
|
+
/** Evaluate a rule tree. An empty group matches everyone. */
|
|
70
|
+
declare function evaluateRules(group: RuleGroup | null | undefined, ctx: TargetingContext): boolean;
|
|
71
|
+
/** Fields whose evaluation requires server-held data. Used by docs/UI to annotate rules. */
|
|
72
|
+
declare const SERVER_ASSISTED_FIELDS: RuleField[];
|
|
73
|
+
declare function describeRule(rule: Rule): string;
|
|
74
|
+
|
|
75
|
+
/** Reserved property names that are stripped from `properties` to avoid collecting sensitive data. */
|
|
76
|
+
declare const SENSITIVE_PROPERTY_PATTERN: RegExp;
|
|
77
|
+
declare const MAX_PROPERTY_BYTES: number;
|
|
78
|
+
declare function sanitizeProperties(props: Record<string, unknown> | undefined): Record<string, unknown>;
|
|
79
|
+
|
|
80
|
+
export { MAX_PROPERTY_BYTES, RULE_FIELDS, RULE_OPERATORS, type Rule, type RuleField, type RuleGroup, type RuleOperator, SENSITIVE_PROPERTY_PATTERN, SERVER_ASSISTED_FIELDS, type TargetingContext, clamp, compare, describeRule, emptyRuleGroup, evaluateRule, evaluateRules, fnv1a, getPath, isPlainObject, isRuleGroup, matchUrlPattern, randomId, rolloutBucket, safeRegExp, sanitizeProperties, slugify, stripOrigin };
|
package/dist/runtime.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MAX_PROPERTY_BYTES,
|
|
3
|
+
RULE_FIELDS,
|
|
4
|
+
RULE_OPERATORS,
|
|
5
|
+
SENSITIVE_PROPERTY_PATTERN,
|
|
6
|
+
SERVER_ASSISTED_FIELDS,
|
|
7
|
+
clamp,
|
|
8
|
+
compare,
|
|
9
|
+
describeRule,
|
|
10
|
+
emptyRuleGroup,
|
|
11
|
+
evaluateRule,
|
|
12
|
+
evaluateRules,
|
|
13
|
+
fnv1a,
|
|
14
|
+
getPath,
|
|
15
|
+
isPlainObject,
|
|
16
|
+
isRuleGroup,
|
|
17
|
+
matchUrlPattern,
|
|
18
|
+
randomId,
|
|
19
|
+
rolloutBucket,
|
|
20
|
+
safeRegExp,
|
|
21
|
+
sanitizeProperties,
|
|
22
|
+
slugify,
|
|
23
|
+
stripOrigin
|
|
24
|
+
} from "./chunk-OFBIZEM5.js";
|
|
25
|
+
export {
|
|
26
|
+
MAX_PROPERTY_BYTES,
|
|
27
|
+
RULE_FIELDS,
|
|
28
|
+
RULE_OPERATORS,
|
|
29
|
+
SENSITIVE_PROPERTY_PATTERN,
|
|
30
|
+
SERVER_ASSISTED_FIELDS,
|
|
31
|
+
clamp,
|
|
32
|
+
compare,
|
|
33
|
+
describeRule,
|
|
34
|
+
emptyRuleGroup,
|
|
35
|
+
evaluateRule,
|
|
36
|
+
evaluateRules,
|
|
37
|
+
fnv1a,
|
|
38
|
+
getPath,
|
|
39
|
+
isPlainObject,
|
|
40
|
+
isRuleGroup,
|
|
41
|
+
matchUrlPattern,
|
|
42
|
+
randomId,
|
|
43
|
+
rolloutBucket,
|
|
44
|
+
safeRegExp,
|
|
45
|
+
sanitizeProperties,
|
|
46
|
+
slugify,
|
|
47
|
+
stripOrigin
|
|
48
|
+
};
|
|
49
|
+
//# sourceMappingURL=runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,65 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@guidelytech/shared",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Shared schemas, types and pure utilities for Guidely",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"sideEffects": false,
|
|
8
|
+
"main": "./dist/index.cjs",
|
|
9
|
+
"module": "./dist/index.js",
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"import": "./dist/index.js",
|
|
15
|
+
"require": "./dist/index.cjs"
|
|
16
|
+
},
|
|
17
|
+
"./runtime": {
|
|
18
|
+
"types": "./dist/runtime.d.ts",
|
|
19
|
+
"import": "./dist/runtime.js",
|
|
20
|
+
"require": "./dist/runtime.cjs"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"dist",
|
|
25
|
+
"README.md"
|
|
26
|
+
],
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"zod": "^3.25.76"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"tsup": "^8.5.1",
|
|
32
|
+
"typescript": "^5.9.3",
|
|
33
|
+
"vitest": "^3.2.7",
|
|
34
|
+
"eslint": "^9.39.5",
|
|
35
|
+
"@eslint/js": "^9.39.5",
|
|
36
|
+
"typescript-eslint": "^8.46.0"
|
|
37
|
+
},
|
|
38
|
+
"publishConfig": {
|
|
39
|
+
"access": "public"
|
|
40
|
+
},
|
|
41
|
+
"repository": {
|
|
42
|
+
"type": "git",
|
|
43
|
+
"url": "git+https://github.com/parmarg/Guidely.git",
|
|
44
|
+
"directory": "packages/shared"
|
|
45
|
+
},
|
|
46
|
+
"homepage": "https://github.com/parmarg/Guidely/tree/main/packages/shared#readme",
|
|
47
|
+
"bugs": {
|
|
48
|
+
"url": "https://github.com/parmarg/Guidely/issues"
|
|
49
|
+
},
|
|
50
|
+
"keywords": [
|
|
51
|
+
"guidely",
|
|
52
|
+
"product-adoption",
|
|
53
|
+
"onboarding",
|
|
54
|
+
"product-tour",
|
|
55
|
+
"in-app-guidance"
|
|
56
|
+
],
|
|
57
|
+
"scripts": {
|
|
58
|
+
"build": "tsup",
|
|
59
|
+
"dev": "tsup --watch",
|
|
60
|
+
"typecheck": "tsc --noEmit",
|
|
61
|
+
"test": "vitest run",
|
|
62
|
+
"lint": "eslint src",
|
|
63
|
+
"clean": "rm -rf dist"
|
|
64
|
+
}
|
|
6
65
|
}
|