@squaredr/fieldcraft-pro 1.6.4 → 1.8.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/LICENSE.txt CHANGED
@@ -1,51 +1,51 @@
1
- SquaredR Commercial License
2
-
3
- Copyright (c) 2024-2026 SquaredR. All rights reserved.
4
-
5
- This software and associated documentation files (the "Software") are the
6
- proprietary property of SquaredR.
7
-
8
- GRANT OF LICENSE
9
-
10
- Subject to the terms of this license and payment of applicable fees, SquaredR
11
- grants you a non-exclusive, non-transferable license to:
12
-
13
- 1. Use the Software in a single production application per license key.
14
- 2. Modify the Software for your own internal use within the licensed
15
- application.
16
- 3. Use the Software in unlimited development and staging environments
17
- without a license key (development mode).
18
-
19
- RESTRICTIONS
20
-
21
- You may NOT:
22
-
23
- 1. Redistribute, sublicense, sell, or otherwise transfer the Software or
24
- any derivative works to third parties.
25
- 2. Remove or alter any copyright notices, license keys, or proprietary
26
- markings in the Software.
27
- 3. Use the Software to build a competing product or service.
28
- 4. Share license keys across organizations or unrelated projects.
29
-
30
- DEVELOPMENT MODE
31
-
32
- The Software may be used without a license key for development and evaluation
33
- purposes. Development mode includes visual watermarks and console notices to
34
- indicate unlicensed usage. Production deployment requires a valid license key.
35
-
36
- DISCLAIMER OF WARRANTIES
37
-
38
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
39
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
40
- FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT. IN NO EVENT SHALL
41
- SQUAREDR BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY ARISING FROM
42
- THE USE OF THE SOFTWARE.
43
-
44
- TERMINATION
45
-
46
- This license is effective until terminated. It will terminate automatically
47
- if you fail to comply with any term. Upon termination, you must destroy all
48
- copies of the Software in your possession.
49
-
50
- For licensing inquiries: support@squaredr.tech
51
- Purchase a license: https://squaredr.tech/products/fieldcraft/admin-pro#pricing
1
+ SquaredR Commercial License
2
+
3
+ Copyright (c) 2024-2026 SquaredR. All rights reserved.
4
+
5
+ This software and associated documentation files (the "Software") are the
6
+ proprietary property of SquaredR.
7
+
8
+ GRANT OF LICENSE
9
+
10
+ Subject to the terms of this license and payment of applicable fees, SquaredR
11
+ grants you a non-exclusive, non-transferable license to:
12
+
13
+ 1. Use the Software in a single production application per license key.
14
+ 2. Modify the Software for your own internal use within the licensed
15
+ application.
16
+ 3. Use the Software in unlimited development and staging environments
17
+ without a license key (development mode).
18
+
19
+ RESTRICTIONS
20
+
21
+ You may NOT:
22
+
23
+ 1. Redistribute, sublicense, sell, or otherwise transfer the Software or
24
+ any derivative works to third parties.
25
+ 2. Remove or alter any copyright notices, license keys, or proprietary
26
+ markings in the Software.
27
+ 3. Use the Software to build a competing product or service.
28
+ 4. Share license keys across organizations or unrelated projects.
29
+
30
+ DEVELOPMENT MODE
31
+
32
+ The Software may be used without a license key for development and evaluation
33
+ purposes. Development mode includes visual watermarks and console notices to
34
+ indicate unlicensed usage. Production deployment requires a valid license key.
35
+
36
+ DISCLAIMER OF WARRANTIES
37
+
38
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
39
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
40
+ FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT. IN NO EVENT SHALL
41
+ SQUAREDR BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY ARISING FROM
42
+ THE USE OF THE SOFTWARE.
43
+
44
+ TERMINATION
45
+
46
+ This license is effective until terminated. It will terminate automatically
47
+ if you fail to comply with any term. Upon termination, you must destroy all
48
+ copies of the Software in your possession.
49
+
50
+ For licensing inquiries: support@squaredr.tech
51
+ Purchase a license: https://squaredr.tech/products/fieldcraft/admin-pro#pricing
package/README.md CHANGED
@@ -1,139 +1,139 @@
1
- # @squaredr/fieldcraft-pro
2
-
3
- [![npm version](https://img.shields.io/npm/v/@squaredr/fieldcraft-pro.svg)](https://www.npmjs.com/package/@squaredr/fieldcraft-pro)
4
- [![license](https://img.shields.io/badge/license-Commercial-blue.svg)](https://squaredr.tech/products/fieldcraft/admin-pro#pricing)
5
-
6
- Pro components for [FieldCraft](https://squaredr.tech/products/fieldcraft) — a schema-driven form engine for React. Build forms visually, view responses, and customize themes without writing code.
7
-
8
- ## What's Included
9
-
10
- | Component | Description |
11
- |-----------|-------------|
12
- | **FormBuilder** | Drag-and-drop visual form designer with 32 field types, undo/redo, import/export, and live preview |
13
- | **ResponseViewer** | Read-only viewer for submitted form data with table and detail views, CSV/JSON export |
14
- | **ThemeEditor** | Visual theme editor for form styling with color pickers, typography controls, and live preview |
15
-
16
- ## Install
17
-
18
- ```bash
19
- npm install @squaredr/fieldcraft-pro @squaredr/fieldcraft-core @squaredr/fieldcraft-react
20
- ```
21
-
22
- ## Quick Start
23
-
24
- ```tsx
25
- import { FieldCraftProProvider, FormBuilder } from "@squaredr/fieldcraft-pro";
26
- import "@squaredr/fieldcraft-pro/styles.css";
27
-
28
- function App() {
29
- return (
30
- <FieldCraftProProvider licenseKey="YOUR_LICENSE_KEY">
31
- <FormBuilder
32
- onSave={(schema) => console.log(schema)}
33
- height="100vh"
34
- />
35
- </FieldCraftProProvider>
36
- );
37
- }
38
- ```
39
-
40
- ## Subpath Imports
41
-
42
- ```tsx
43
- // Root — everything
44
- import { FormBuilder, ResponseViewer, ThemeEditor } from "@squaredr/fieldcraft-pro";
45
-
46
- // Tree-shakeable subpath imports
47
- import { FormBuilder } from "@squaredr/fieldcraft-pro/form-builder";
48
- import { ResponseViewer } from "@squaredr/fieldcraft-pro/response-viewer";
49
- import { ThemeEditor } from "@squaredr/fieldcraft-pro/theme-editor";
50
-
51
- // CSS
52
- import "@squaredr/fieldcraft-pro/styles.css"; // Form Builder styles
53
- import "@squaredr/fieldcraft-pro/theme-editor/styles.css"; // Theme Editor styles
54
- ```
55
-
56
- ## Form Builder
57
-
58
- Visual form designer with drag-and-drop, live preview, and schema export:
59
-
60
- ```tsx
61
- import { FormBuilder } from "@squaredr/fieldcraft-pro";
62
-
63
- <FormBuilder
64
- onSave={(schema) => saveToServer(schema)}
65
- onChange={(schema) => setPreview(schema)}
66
- height="100vh"
67
- />
68
- ```
69
-
70
- ### Field Types (32)
71
-
72
- | Category | Fields |
73
- |----------|--------|
74
- | Text | Short Text, Long Text, Email, Phone, URL |
75
- | Numeric | Number, Slider, Rating, NPS, Opinion Scale |
76
- | Selection | Single Select, Multi Select, Dropdown, Yes/No, Ranking |
77
- | Date/Time | Date, Time |
78
- | Media | File Upload |
79
- | Content | Welcome Screen, Thank You Screen, Rich Text, Image, Video, Divider, Spacer |
80
- | Structural | Section Header, Info Block, Page Break, Consent |
81
- | Advanced | Matrix, Calculated, Hidden |
82
-
83
- ### Extending with Custom Fields
84
-
85
- The FormBuilder accepts `questionTypes` and `palette` props to inject additional field types at runtime:
86
-
87
- ```tsx
88
- import { FormBuilder, QUESTION_TYPE_INFO, DEFAULT_PALETTE } from "@squaredr/fieldcraft-pro";
89
-
90
- <FormBuilder
91
- questionTypes={{ ...QUESTION_TYPE_INFO, ...myCustomTypes }}
92
- palette={[...DEFAULT_PALETTE, ...myCustomCategories]}
93
- />
94
- ```
95
-
96
- ## Response Viewer
97
-
98
- Display submitted form responses in table or card/detail views:
99
-
100
- ```tsx
101
- import { ResponseViewer } from "@squaredr/fieldcraft-pro";
102
-
103
- <ResponseViewer
104
- schema={schema}
105
- responses={responses}
106
- onExport={(format) => console.log(`Export as ${format}`)}
107
- />
108
- ```
109
-
110
- ## Theme Editor
111
-
112
- Live-edit form themes with color pickers, typography controls, and shape/spacing sliders:
113
-
114
- ```tsx
115
- import { ThemeEditor } from "@squaredr/fieldcraft-pro";
116
-
117
- <ThemeEditor
118
- onChange={(theme) => console.log(theme)}
119
- onSave={(theme) => saveToServer(theme)}
120
- />
121
- ```
122
-
123
- Includes presets: Clean, Dark, Modern, High Contrast, Clinical, Playful.
124
-
125
- ## Requirements
126
-
127
- - React 18 or 19
128
- - `@squaredr/fieldcraft-core` >= 1.3.3
129
- - `@squaredr/fieldcraft-react` >= 1.2.8
130
-
131
- ## License
132
-
133
- Commercial license required for production use. Free in development mode.
134
-
135
- See [LICENSE.txt](./LICENSE.txt) for details.
136
-
137
- ---
138
-
139
- [Get a license](https://squaredr.tech/products/fieldcraft/admin-pro#pricing) | [Documentation](https://squaredr.tech/products/fieldcraft/docs/pro) | [GitHub](https://github.com/SquaredR98/fieldcraft-pro) | [Discord](https://discord.gg/squaredr)
1
+ # @squaredr/fieldcraft-pro
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@squaredr/fieldcraft-pro.svg)](https://www.npmjs.com/package/@squaredr/fieldcraft-pro)
4
+ [![license](https://img.shields.io/badge/license-Commercial-blue.svg)](https://fieldcraft.squaredr.tech/pro#pricing)
5
+
6
+ Pro components for [FieldCraft](https://fieldcraft.squaredr.tech) — a schema-driven form engine for React. Build forms visually, view responses, and customize themes without writing code.
7
+
8
+ ## What's Included
9
+
10
+ | Component | Description |
11
+ |-----------|-------------|
12
+ | **FormBuilder** | Drag-and-drop visual form designer with 44 field types, undo/redo, import/export, and live preview |
13
+ | **ResponseViewer** | Read-only viewer for submitted form data with table and detail views, CSV/JSON export |
14
+ | **ThemeEditor** | Visual theme editor for form styling with color pickers, typography controls, and live preview |
15
+
16
+ ## Install
17
+
18
+ ```bash
19
+ npm install @squaredr/fieldcraft-pro @squaredr/fieldcraft-core @squaredr/fieldcraft-react
20
+ ```
21
+
22
+ ## Quick Start
23
+
24
+ ```tsx
25
+ import { FieldCraftProProvider, FormBuilder } from "@squaredr/fieldcraft-pro";
26
+ import "@squaredr/fieldcraft-pro/styles.css";
27
+
28
+ function App() {
29
+ return (
30
+ <FieldCraftProProvider licenseKey="YOUR_LICENSE_KEY">
31
+ <FormBuilder
32
+ onSave={(schema) => console.log(schema)}
33
+ height="100vh"
34
+ />
35
+ </FieldCraftProProvider>
36
+ );
37
+ }
38
+ ```
39
+
40
+ ## Subpath Imports
41
+
42
+ ```tsx
43
+ // Root — everything
44
+ import { FormBuilder, ResponseViewer, ThemeEditor } from "@squaredr/fieldcraft-pro";
45
+
46
+ // Tree-shakeable subpath imports
47
+ import { FormBuilder } from "@squaredr/fieldcraft-pro/form-builder";
48
+ import { ResponseViewer } from "@squaredr/fieldcraft-pro/response-viewer";
49
+ import { ThemeEditor } from "@squaredr/fieldcraft-pro/theme-editor";
50
+
51
+ // CSS
52
+ import "@squaredr/fieldcraft-pro/styles.css"; // Form Builder styles
53
+ import "@squaredr/fieldcraft-pro/theme-editor/styles.css"; // Theme Editor styles
54
+ ```
55
+
56
+ ## Form Builder
57
+
58
+ Visual form designer with drag-and-drop, live preview, and schema export:
59
+
60
+ ```tsx
61
+ import { FormBuilder } from "@squaredr/fieldcraft-pro";
62
+
63
+ <FormBuilder
64
+ onSave={(schema) => saveToServer(schema)}
65
+ onChange={(schema) => setPreview(schema)}
66
+ height="100vh"
67
+ />
68
+ ```
69
+
70
+ ### Field Types (42)
71
+
72
+ | Category | Fields |
73
+ |----------|--------|
74
+ | Text | Short Text, Long Text, Email, Phone, URL, Password |
75
+ | Numeric | Number, Slider, Rating, NPS, Opinion Scale, Currency |
76
+ | Selection | Single Select, Multi Select, Dropdown, Yes/No, Ranking, Checkbox Group |
77
+ | Date/Time | Date, Time, Date Range, Date of Birth |
78
+ | Media | File Upload, Signature, Image Capture |
79
+ | Content | Welcome Screen, Thank You Screen, Rich Text, Image, Video, Divider, Spacer |
80
+ | Structural | Section Header, Info Block, Page Break, Consent |
81
+ | Advanced | Matrix, Calculated, Hidden, Repeater, Address, Legal Name, Country Select |
82
+
83
+ ### Extending with Custom Fields
84
+
85
+ The FormBuilder accepts `questionTypes` and `palette` props to inject additional field types at runtime:
86
+
87
+ ```tsx
88
+ import { FormBuilder, QUESTION_TYPE_INFO, DEFAULT_PALETTE } from "@squaredr/fieldcraft-pro";
89
+
90
+ <FormBuilder
91
+ questionTypes={{ ...QUESTION_TYPE_INFO, ...myCustomTypes }}
92
+ palette={[...DEFAULT_PALETTE, ...myCustomCategories]}
93
+ />
94
+ ```
95
+
96
+ ## Response Viewer
97
+
98
+ Display submitted form responses in table or card/detail views:
99
+
100
+ ```tsx
101
+ import { ResponseViewer } from "@squaredr/fieldcraft-pro";
102
+
103
+ <ResponseViewer
104
+ schema={schema}
105
+ responses={responses}
106
+ onExport={(format) => console.log(`Export as ${format}`)}
107
+ />
108
+ ```
109
+
110
+ ## Theme Editor
111
+
112
+ Live-edit form themes with color pickers, typography controls, and shape/spacing sliders:
113
+
114
+ ```tsx
115
+ import { ThemeEditor } from "@squaredr/fieldcraft-pro";
116
+
117
+ <ThemeEditor
118
+ onChange={(theme) => console.log(theme)}
119
+ onSave={(theme) => saveToServer(theme)}
120
+ />
121
+ ```
122
+
123
+ Includes presets: Clean, Dark, Modern, High Contrast, Clinical, Playful.
124
+
125
+ ## Requirements
126
+
127
+ - React 18 or 19
128
+ - `@squaredr/fieldcraft-core` >= 1.6.0
129
+ - `@squaredr/fieldcraft-react` >= 1.6.0
130
+
131
+ ## License
132
+
133
+ Commercial license required for production use. Free in development mode.
134
+
135
+ See [LICENSE.txt](./LICENSE.txt) for details.
136
+
137
+ ---
138
+
139
+ [Get a license](https://fieldcraft.squaredr.tech/pro#pricing) | [Documentation](https://fieldcraft.squaredr.tech/docs) | [GitHub](https://github.com/SquaredR98/fieldcraft-pro) | [Discord](https://discord.gg/squaredr)
@@ -2,37 +2,16 @@ import { createContext, useState, useEffect, useContext } from 'react';
2
2
  import { jsx, jsxs } from 'react/jsx-runtime';
3
3
 
4
4
  // ../license/dist/index.mjs
5
+ var PRODUCT_IDS = {
6
+ FIELDCRAFT_PRO: 1
7
+ };
5
8
  var LEGACY_TIER_MAP = {
6
9
  "01": "starter",
7
10
  "02": "pro",
8
11
  "03": "business",
9
12
  "04": "enterprise"
10
13
  };
11
- var TIER_MAP_NUMERIC = {
12
- 1: "starter",
13
- 2: "pro",
14
- 3: "business",
15
- 4: "enterprise"
16
- };
17
- var PRO_FEATURES = [
18
- "SchemaEditor",
19
- "ResponseViewer",
20
- "ThemeEditor",
21
- "FormBuilder",
22
- "ApiManager",
23
- "Analytics"
24
- ];
25
- var ALL_FEATURES = [
26
- ...PRO_FEATURES,
27
- "Telehealth"
28
- ];
29
- var TIER_FEATURES = {
30
- starter: ["SchemaEditor", "ResponseViewer"],
31
- pro: PRO_FEATURES,
32
- business: ALL_FEATURES,
33
- enterprise: ALL_FEATURES
34
- };
35
- var HMAC_SECRET = "e50a657813a5ab9563050728a605b9ab58b911d5c1a9f48c6825f379a533ccd7685d11d01937d9f135776a0db3efeefe29b3e5282b27ede8cee93758f94f2d75";
14
+ var HMAC_SECRET = "15bb3af8d82d01de70ab556c5785fd92461e336b941ed65cf99834d5e99924e742db9a9197056b531bf0f429df621be17cb71d8ba5e892075e1b4283969657dc3bbf4d0287cf15804d5482510b8a405bb33a69249e8007a8a3c2af0d499423623dafecb719d985a4ad8e2edf8623936db90387ea3139f8d0eeb2556e408a0d6de69c034e33e1e6a0633af0eeeb63dd13f4711ba0a0aacc3af6b87bdace13a7886013d3a5410817966f0af7230f277b6207ad5de2916f6c0bfab5c2a18ccfe72d513bb726206d8929e8b01d91f6bf38572c0f238302c4fdf0263c7bd0c48cf0e1678f94de727b61388c672c11e82ecb96591d264731177d7588d92cdf70ea46a2";
36
15
  var B32_CHARS = "0123456789ABCDEFGHIJKLMNOPQRSTUV";
37
16
  function base32hexDecode(str) {
38
17
  const upper = str.toUpperCase();
@@ -66,14 +45,15 @@ function parseOpaqueKey(key) {
66
45
  if (!stripped.startsWith("FCPRO")) return null;
67
46
  const encoded = stripped.slice(5);
68
47
  const decoded = base32hexDecode(encoded);
69
- if (!decoded || decoded.length < 17) return null;
70
- const tier = decoded[0];
71
- if (!(tier in TIER_MAP_NUMERIC)) return null;
72
- const expiryTimestamp = decoded[1] << 24 | decoded[2] << 16 | decoded[3] << 8 | decoded[4];
73
- const expiryUnsigned = expiryTimestamp >>> 0;
74
- const nonce = decoded.slice(5, 9);
75
- const signature = decoded.slice(9, 17);
76
- return { format: "opaque", tier, expiryTimestamp: expiryUnsigned, nonce, signature };
48
+ if (!decoded || decoded.length < 25) return null;
49
+ const productId = decoded[0];
50
+ if (productId !== PRODUCT_IDS.FIELDCRAFT_PRO) return null;
51
+ const purchaseTimestamp = (decoded[1] << 24 | decoded[2] << 16 | decoded[3] << 8 | decoded[4]) >>> 0;
52
+ const expiryTimestamp = (decoded[5] << 24 | decoded[6] << 16 | decoded[7] << 8 | decoded[8]) >>> 0;
53
+ const emailHash = decoded.slice(9, 13);
54
+ const nonce = decoded.slice(13, 17);
55
+ const signature = decoded.slice(17, 25);
56
+ return { format: "opaque", productId, purchaseTimestamp, expiryTimestamp, emailHash, nonce, signature };
77
57
  }
78
58
  function parseKey(key) {
79
59
  if (!key || typeof key !== "string") return null;
@@ -119,54 +99,52 @@ function isExpiredOpaque(expiryTimestamp) {
119
99
  if (expiryTimestamp === 4294967295) return false;
120
100
  return Date.now() / 1e3 > expiryTimestamp;
121
101
  }
102
+ function timingSafeEqual(a, b) {
103
+ if (a.length !== b.length) return false;
104
+ let result = 0;
105
+ for (let i = 0; i < a.length; i++) {
106
+ result |= a[i] ^ b[i];
107
+ }
108
+ return result === 0;
109
+ }
122
110
  async function validateLicense(key) {
123
111
  if (!key || typeof key !== "string") {
124
- return { status: "invalid", tier: null };
112
+ return { status: "invalid" };
125
113
  }
126
114
  const parsed = parseKey(key);
127
115
  if (!parsed) {
128
- return { status: "invalid", tier: null };
116
+ return { status: "invalid" };
129
117
  }
130
118
  if (parsed.format === "opaque") {
131
- const payload = new Uint8Array(9);
132
- payload[0] = parsed.tier;
133
- payload[1] = parsed.expiryTimestamp >>> 24 & 255;
134
- payload[2] = parsed.expiryTimestamp >>> 16 & 255;
135
- payload[3] = parsed.expiryTimestamp >>> 8 & 255;
136
- payload[4] = parsed.expiryTimestamp & 255;
137
- payload.set(parsed.nonce, 5);
119
+ const payload = new Uint8Array(17);
120
+ payload[0] = parsed.productId;
121
+ payload[1] = parsed.purchaseTimestamp >>> 24 & 255;
122
+ payload[2] = parsed.purchaseTimestamp >>> 16 & 255;
123
+ payload[3] = parsed.purchaseTimestamp >>> 8 & 255;
124
+ payload[4] = parsed.purchaseTimestamp & 255;
125
+ payload[5] = parsed.expiryTimestamp >>> 24 & 255;
126
+ payload[6] = parsed.expiryTimestamp >>> 16 & 255;
127
+ payload[7] = parsed.expiryTimestamp >>> 8 & 255;
128
+ payload[8] = parsed.expiryTimestamp & 255;
129
+ payload.set(parsed.emailHash, 9);
130
+ payload.set(parsed.nonce, 13);
138
131
  const expectedSig = await computeHmacOpaque(payload);
139
- let match = true;
140
- for (let i = 0; i < 8; i++) {
141
- if (parsed.signature[i] !== expectedSig[i]) {
142
- match = false;
143
- break;
144
- }
145
- }
146
- if (!match) {
147
- return { status: "invalid", tier: null };
148
- }
149
- const tier2 = TIER_MAP_NUMERIC[parsed.tier];
150
- if (!tier2) {
151
- return { status: "invalid", tier: null };
132
+ if (!timingSafeEqual(parsed.signature, expectedSig)) {
133
+ return { status: "invalid" };
152
134
  }
153
135
  if (isExpiredOpaque(parsed.expiryTimestamp)) {
154
- return { status: "expired", tier: tier2 };
136
+ return { status: "expired" };
155
137
  }
156
- return { status: "valid", tier: tier2 };
138
+ return { status: "valid" };
157
139
  }
158
140
  const expectedHash = await computeHmacLegacy(parsed.tierHex, parsed.expiryHex);
159
141
  if (parsed.hash.toUpperCase() !== expectedHash) {
160
- return { status: "invalid", tier: null };
142
+ return { status: "invalid" };
161
143
  }
162
- const tier = LEGACY_TIER_MAP[parsed.tierHex];
163
144
  if (isExpiredLegacy(parsed.expiryHex)) {
164
- return { status: "expired", tier };
145
+ return { status: "expired" };
165
146
  }
166
- return { status: "valid", tier };
167
- }
168
- function tierHasFeature(tier, featureName) {
169
- return TIER_FEATURES[tier]?.includes(featureName) ?? false;
147
+ return { status: "valid" };
170
148
  }
171
149
  var DEV_HOSTNAMES = /* @__PURE__ */ new Set([
172
150
  "localhost",
@@ -239,7 +217,7 @@ function isProductionEnvironment() {
239
217
  }
240
218
  return false;
241
219
  }
242
- var PING_URL = "https://squaredr.tech/api/license/ping";
220
+ var PING_URL = typeof process !== "undefined" && process.env?.NEXT_PUBLIC_FCPRO_PING_URL || "https://fieldcraft.dev/api/license/ping";
243
221
  var CACHE_KEY = "fcpro_lp";
244
222
  var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
245
223
  function hashKey(key) {
@@ -267,10 +245,10 @@ function readCache(key) {
267
245
  return null;
268
246
  }
269
247
  }
270
- function writeCache(key, status, tier, reason = null) {
248
+ function writeCache(key, status, reason = null) {
271
249
  if (typeof window === "undefined" || !window.localStorage) return;
272
250
  try {
273
- const entry = { s: status, t: tier, r: reason, ts: Date.now() };
251
+ const entry = { s: status, r: reason, ts: Date.now() };
274
252
  localStorage.setItem(cacheId(key), JSON.stringify(entry));
275
253
  } catch {
276
254
  }
@@ -278,12 +256,12 @@ function writeCache(key, status, tier, reason = null) {
278
256
  function getCachedPingResult(key) {
279
257
  const cached = readCache(key);
280
258
  if (!cached) return null;
281
- return { status: cached.s, tier: cached.t, reason: cached.r || void 0 };
259
+ return { status: cached.s, reason: cached.r || void 0 };
282
260
  }
283
261
  async function performPing(key) {
284
262
  const cached = readCache(key);
285
263
  if (cached) {
286
- return { status: cached.s, tier: cached.t };
264
+ return { status: cached.s };
287
265
  }
288
266
  try {
289
267
  const controller = new AbortController();
@@ -297,29 +275,28 @@ async function performPing(key) {
297
275
  clearTimeout(timeout);
298
276
  if (!res.ok) return null;
299
277
  const data = await res.json();
300
- const tier = data.tier || null;
301
278
  if (data.status === "active") {
302
- writeCache(key, "valid", tier);
303
- return { status: "valid", tier };
279
+ writeCache(key, "valid");
280
+ return { status: "valid" };
304
281
  }
305
282
  if (data.status === "revoked") {
306
- writeCache(key, "revoked", null, data.reason);
307
- return { status: "revoked", tier: null, reason: data.reason };
283
+ writeCache(key, "revoked", data.reason);
284
+ return { status: "revoked", reason: data.reason };
308
285
  }
309
286
  if (data.status === "expired") {
310
- writeCache(key, "expired", tier);
311
- return { status: "expired", tier };
287
+ writeCache(key, "expired");
288
+ return { status: "expired" };
312
289
  }
313
290
  if (data.status === "domain_mismatch") {
314
- writeCache(key, "domain_mismatch", null, data.reason);
315
- return { status: "domain_mismatch", tier: null, reason: data.reason };
291
+ writeCache(key, "domain_mismatch", data.reason);
292
+ return { status: "domain_mismatch", reason: data.reason };
316
293
  }
317
294
  return null;
318
295
  } catch {
319
296
  return null;
320
297
  }
321
298
  }
322
- var defaultContext = { status: "validating", tier: null };
299
+ var defaultContext = { status: "validating" };
323
300
  var LicenseCtx = createContext(defaultContext);
324
301
  function FieldCraftProProvider({ licenseKey, children }) {
325
302
  const [license, setLicense] = useState(defaultContext);
@@ -333,7 +310,7 @@ function FieldCraftProProvider({ licenseKey, children }) {
333
310
  const cached = getCachedPingResult(licenseKey);
334
311
  if (cached) {
335
312
  if (cached.status === "revoked" || cached.status === "domain_mismatch") {
336
- setLicense({ status: cached.status, tier: null });
313
+ setLicense({ status: cached.status });
337
314
  }
338
315
  return;
339
316
  }
@@ -341,7 +318,7 @@ function FieldCraftProProvider({ licenseKey, children }) {
341
318
  if (cancelled) return;
342
319
  if (!pingResult) return;
343
320
  if (pingResult.status === "revoked" || pingResult.status === "domain_mismatch") {
344
- setLicense({ status: pingResult.status, tier: null });
321
+ setLicense({ status: pingResult.status });
345
322
  }
346
323
  });
347
324
  });
@@ -549,7 +526,7 @@ function UnlicensedOverlay({ featureName, reason, children }) {
549
526
  }
550
527
  function requireLicense(Component, featureName) {
551
528
  function LicenseGated(props) {
552
- const { status, tier } = useLicense();
529
+ const { status } = useLicense();
553
530
  const isProduction = isProductionEnvironment();
554
531
  if (!isProduction) {
555
532
  return /* @__PURE__ */ jsx(Component, { ...props });
@@ -557,8 +534,7 @@ function requireLicense(Component, featureName) {
557
534
  if (status === "validating") {
558
535
  return null;
559
536
  }
560
- const isLicensed = status === "valid" && tier != null && tierHasFeature(tier, featureName);
561
- if (isLicensed) {
537
+ if (status === "valid") {
562
538
  return /* @__PURE__ */ jsx(Component, { ...props });
563
539
  }
564
540
  let reason = "A valid license is required for production use.";
@@ -570,8 +546,6 @@ function requireLicense(Component, featureName) {
570
546
  reason = "This license key has been revoked. Please contact support or purchase a new license.";
571
547
  } else if (status === "domain_mismatch") {
572
548
  reason = "This license key is registered to a different domain. Each key can only be used on one production domain. Please purchase a new license for this domain.";
573
- } else if (!tier || !tierHasFeature(tier, featureName)) {
574
- reason = "Your license does not include this feature. Please upgrade your plan.";
575
549
  }
576
550
  return /* @__PURE__ */ jsx(UnlicensedOverlay, { featureName, reason, children: /* @__PURE__ */ jsx(Component, { ...props }) });
577
551
  }