@designbasekorea/figma-license-core 0.3.2 → 0.4.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 +4 -0
- package/dist/fetchLicenseTransport.d.ts.map +1 -1
- package/dist/figmaStatusManager.d.ts +20 -0
- package/dist/figmaStatusManager.d.ts.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.js +268 -17
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +272 -16
- package/dist/index.js.map +1 -1
- package/dist/index.umd.js +272 -16
- package/dist/index.umd.js.map +1 -1
- package/dist/licenseCore.d.ts.map +1 -1
- package/dist/licenseErrorMapper.d.ts.map +1 -1
- package/dist/licenseMigration.d.ts +12 -0
- package/dist/licenseMigration.d.ts.map +1 -0
- package/dist/wordpressLicenseTransport.d.ts +11 -0
- package/dist/wordpressLicenseTransport.d.ts.map +1 -0
- package/docs/WORDPRESS_GATEWAY.md +81 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -54,6 +54,7 @@ function asText(input) {
|
|
|
54
54
|
function inferCode(text) {
|
|
55
55
|
const normalized = text.toLowerCase();
|
|
56
56
|
if (normalized.includes('activation limit')
|
|
57
|
+
|| normalized.includes('activation_limit_reached')
|
|
57
58
|
|| normalized.includes('seat')
|
|
58
59
|
|| normalized.includes('too many activations')
|
|
59
60
|
|| normalized.includes('already activated on maximum')) {
|
|
@@ -164,7 +165,7 @@ function validationMessage(result) {
|
|
|
164
165
|
return '이 멤버십 라이선스는 철회되었습니다.';
|
|
165
166
|
case 'expired':
|
|
166
167
|
case 'license_expired':
|
|
167
|
-
return '
|
|
168
|
+
return '라이선스가 만료되었습니다. 새 키를 확인해 주세요.';
|
|
168
169
|
case 'not_started':
|
|
169
170
|
return '이 멤버십 라이선스는 아직 시작되지 않았습니다.';
|
|
170
171
|
case 'rate_limited':
|
|
@@ -181,6 +182,8 @@ function validationMessage(result) {
|
|
|
181
182
|
function validationErrorCode(result) {
|
|
182
183
|
const status = (result.errorCode || result.licenseStatus || '').toLowerCase();
|
|
183
184
|
switch (status) {
|
|
185
|
+
case 'activation_limit_reached':
|
|
186
|
+
return exports.LicenseErrorCode.ACTIVATION_LIMIT_REACHED;
|
|
184
187
|
case 'expired':
|
|
185
188
|
case 'license_expired':
|
|
186
189
|
return exports.LicenseErrorCode.LICENSE_EXPIRED;
|
|
@@ -291,7 +294,7 @@ class LicenseCore {
|
|
|
291
294
|
}
|
|
292
295
|
async initialize() {
|
|
293
296
|
let state = await this.getStatus();
|
|
294
|
-
if (state.
|
|
297
|
+
if (state.licenseKey && state.licenseKey !== this.config.masterCode) {
|
|
295
298
|
try {
|
|
296
299
|
const validateResult = this.deps.transport.validate
|
|
297
300
|
? await this.deps.transport.validate({
|
|
@@ -432,10 +435,12 @@ class LicenseCore {
|
|
|
432
435
|
}
|
|
433
436
|
let verifyResult;
|
|
434
437
|
try {
|
|
438
|
+
const current = await this.getStatus();
|
|
435
439
|
verifyResult = await this.deps.transport.verify({
|
|
436
440
|
licenseKey: trimmedLicenseKey,
|
|
437
441
|
productId: this.config.productId,
|
|
438
442
|
instanceName: this.config.instanceName,
|
|
443
|
+
instanceId: current.licenseKey === trimmedLicenseKey ? current.instanceId : undefined,
|
|
439
444
|
});
|
|
440
445
|
}
|
|
441
446
|
catch (error) {
|
|
@@ -451,7 +456,9 @@ class LicenseCore {
|
|
|
451
456
|
}
|
|
452
457
|
const activationLimit = toNonNegativeNumber(verifyResult.activationLimit, 0);
|
|
453
458
|
const activationUsage = toNonNegativeNumber(verifyResult.activationUsage, 0);
|
|
454
|
-
|
|
459
|
+
// A verified instance already occupies its seat. usage === limit is not
|
|
460
|
+
// an error after successful activation (e.g. the first device on a 1-seat key).
|
|
461
|
+
if (!verifyResult.instanceId && isActivationLimitReached(activationLimit, activationUsage)) {
|
|
455
462
|
throw new LicenseCoreError(exports.LicenseErrorCode.ACTIVATION_LIMIT_REACHED, '활성화 가능한 기기 수를 모두 사용했습니다. 기존 기기를 비활성화한 뒤 다시 시도해 주세요.', verifyResult);
|
|
456
463
|
}
|
|
457
464
|
const current = await this.getStatus();
|
|
@@ -791,12 +798,14 @@ function asRecord$1(value) {
|
|
|
791
798
|
}
|
|
792
799
|
function failureMessageForStatus(status) {
|
|
793
800
|
switch (status) {
|
|
801
|
+
case 'activation_limit_reached':
|
|
802
|
+
return '이 라이선스의 활성화 기기 수를 초과했습니다. 기존 기기에서 먼저 비활성화해 주세요.';
|
|
794
803
|
case 'not_started':
|
|
795
804
|
return '이번 달 라이선스의 사용 기간이 아직 시작되지 않았습니다.';
|
|
796
805
|
case 'expired':
|
|
797
|
-
return '라이선스가 만료되었습니다.
|
|
806
|
+
return '라이선스가 만료되었습니다. 새 키를 확인해 주세요.';
|
|
798
807
|
case 'revoked':
|
|
799
|
-
return '사용 중지된 라이선스입니다.
|
|
808
|
+
return '사용 중지된 라이선스입니다. 구매 내역이나 관리자에게 문의해 주세요.';
|
|
800
809
|
case 'product_not_allowed':
|
|
801
810
|
return '이 라이선스는 현재 플러그인에서 사용할 수 없습니다.';
|
|
802
811
|
case 'rate_limited':
|
|
@@ -812,9 +821,12 @@ function defaultNormalizeVerifyResponse(raw) {
|
|
|
812
821
|
const statusValid = typeof licenseStatus === 'string'
|
|
813
822
|
? licenseStatus.toLowerCase() === 'active'
|
|
814
823
|
: undefined;
|
|
815
|
-
const
|
|
824
|
+
const rejectedStatus = ['expired', 'revoked', 'invalid', 'inactive', 'not_started',
|
|
825
|
+
'product_not_allowed', 'rate_limited', 'activation_limit_reached', 'environment_mismatch', 'mode_unverified']
|
|
826
|
+
.includes(licenseStatus?.trim().toLowerCase() || '');
|
|
827
|
+
const valid = !rejectedStatus && (readBooleanField(body, ['valid', 'success', 'active'])
|
|
816
828
|
?? statusValid
|
|
817
|
-
?? false;
|
|
829
|
+
?? false);
|
|
818
830
|
const normalizedStatus = licenseStatus?.trim().toLowerCase();
|
|
819
831
|
const fallbackMessage = !valid ? failureMessageForStatus(normalizedStatus) : undefined;
|
|
820
832
|
const message = readTextField(body, ['message', 'error', 'detail']) || fallbackMessage;
|
|
@@ -1189,6 +1201,205 @@ class DesignbaseAccountLicenseTransport {
|
|
|
1189
1201
|
}
|
|
1190
1202
|
}
|
|
1191
1203
|
|
|
1204
|
+
/** Copy legacy storage once. Paid status is revalidated before any UI is published. */
|
|
1205
|
+
async function migrateLegacyLicenseStorage(storage, prefix, keys = {}) {
|
|
1206
|
+
const oldKey = (field) => {
|
|
1207
|
+
const oldPrefix = keys.sourcePrefix ? `${keys.sourcePrefix}:` : '';
|
|
1208
|
+
return `${oldPrefix}${keys[field] || field}`;
|
|
1209
|
+
};
|
|
1210
|
+
const marker = `${prefix}:legacyMigration`;
|
|
1211
|
+
if (await storage.get(marker))
|
|
1212
|
+
return;
|
|
1213
|
+
const existing = await storage.get(`${prefix}:paymentStatus`);
|
|
1214
|
+
if (existing === undefined || existing === null) {
|
|
1215
|
+
const key = await storage.get(oldKey('licenseKey'));
|
|
1216
|
+
const instanceId = await storage.get(oldKey('instanceId'));
|
|
1217
|
+
const paymentStatus = await storage.get(oldKey('paymentStatus'));
|
|
1218
|
+
const usage = await storage.get(oldKey('usageCount'));
|
|
1219
|
+
if (typeof key === 'string' && key.trim()) {
|
|
1220
|
+
await storage.set(`${prefix}:licenseKey`, key.trim());
|
|
1221
|
+
await storage.set(`${prefix}:instanceId`, typeof instanceId === 'string' ? instanceId : '');
|
|
1222
|
+
await storage.set(`${prefix}:planTier`, paymentStatus === 'PAID' ? 'PAID' : 'FREE');
|
|
1223
|
+
}
|
|
1224
|
+
if (typeof usage === 'number' && Number.isFinite(usage) && usage >= 0) {
|
|
1225
|
+
await storage.set(`${prefix}:usageCount`, Math.floor(usage));
|
|
1226
|
+
}
|
|
1227
|
+
if (typeof key === 'string' && key.trim()) {
|
|
1228
|
+
await storage.set(`${prefix}:paymentStatus`, paymentStatus === 'PAID' ? 'PAID' : 'FREE');
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
// Do not delete legacy keys: another version may still need them for rollback.
|
|
1232
|
+
await storage.set(marker, 1);
|
|
1233
|
+
}
|
|
1234
|
+
async function readOrCreateDeviceId(storage, prefix) {
|
|
1235
|
+
const storageKey = `${prefix}:deviceId`;
|
|
1236
|
+
const current = await storage.get(storageKey);
|
|
1237
|
+
if (typeof current === 'string' && current.length > 0)
|
|
1238
|
+
return current;
|
|
1239
|
+
const legacy = await storage.get('licenseDeviceId');
|
|
1240
|
+
const nonce = `${Math.random().toString(36).slice(2)}-${Math.random().toString(36).slice(2)}`;
|
|
1241
|
+
const device = typeof legacy === 'string' && legacy.length > 0
|
|
1242
|
+
? legacy
|
|
1243
|
+
: `license-${Date.now().toString(36)}-${nonce}`;
|
|
1244
|
+
await storage.set(storageKey, device);
|
|
1245
|
+
return device;
|
|
1246
|
+
}
|
|
1247
|
+
const pendingDeviceIds = new WeakMap();
|
|
1248
|
+
async function getPersistentLicenseDeviceId(storage, prefix) {
|
|
1249
|
+
let pending = pendingDeviceIds.get(storage);
|
|
1250
|
+
if (!pending) {
|
|
1251
|
+
pending = new Map();
|
|
1252
|
+
pendingDeviceIds.set(storage, pending);
|
|
1253
|
+
}
|
|
1254
|
+
const existing = pending.get(prefix);
|
|
1255
|
+
if (existing)
|
|
1256
|
+
return existing;
|
|
1257
|
+
const request = readOrCreateDeviceId(storage, prefix);
|
|
1258
|
+
pending.set(prefix, request);
|
|
1259
|
+
try {
|
|
1260
|
+
return await request;
|
|
1261
|
+
}
|
|
1262
|
+
finally {
|
|
1263
|
+
pending.delete(prefix);
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1267
|
+
const errors = {
|
|
1268
|
+
expired: [
|
|
1269
|
+
exports.LicenseErrorCode.LICENSE_EXPIRED,
|
|
1270
|
+
'라이선스가 만료되었습니다. 구매 내역 또는 이번 달 멤버십 키를 확인해 주세요.',
|
|
1271
|
+
],
|
|
1272
|
+
revoked: [exports.LicenseErrorCode.LICENSE_REVOKED, '사용 중지된 라이선스입니다.'],
|
|
1273
|
+
not_started: [
|
|
1274
|
+
exports.LicenseErrorCode.INVALID_LICENSE,
|
|
1275
|
+
'라이선스 사용 기간이 아직 시작되지 않았습니다.',
|
|
1276
|
+
],
|
|
1277
|
+
product_not_allowed: [
|
|
1278
|
+
exports.LicenseErrorCode.PRODUCT_MISMATCH,
|
|
1279
|
+
'이 라이선스는 현재 플러그인 구매 키가 아닙니다.',
|
|
1280
|
+
],
|
|
1281
|
+
environment_mismatch: [
|
|
1282
|
+
exports.LicenseErrorCode.INVALID_LICENSE,
|
|
1283
|
+
'테스트 구매 키는 테스트 인증 서버에서만 사용할 수 있습니다.',
|
|
1284
|
+
],
|
|
1285
|
+
mode_unverified: [
|
|
1286
|
+
exports.LicenseErrorCode.NETWORK_ERROR,
|
|
1287
|
+
'라이선스의 테스트·운영 구분을 확인하지 못했습니다.',
|
|
1288
|
+
],
|
|
1289
|
+
rate_limited: [
|
|
1290
|
+
exports.LicenseErrorCode.RATE_LIMITED,
|
|
1291
|
+
'인증 요청이 너무 많습니다. 잠시 후 다시 시도해 주세요.',
|
|
1292
|
+
],
|
|
1293
|
+
network_error: [
|
|
1294
|
+
exports.LicenseErrorCode.NETWORK_ERROR,
|
|
1295
|
+
'라이선스 서버에 연결하지 못했습니다. 다시 시도해 주세요.',
|
|
1296
|
+
],
|
|
1297
|
+
activation_limit_reached: [
|
|
1298
|
+
exports.LicenseErrorCode.ACTIVATION_LIMIT_REACHED,
|
|
1299
|
+
'사용 가능한 기기 수를 모두 사용했습니다. 다른 기기에서 해제해 주세요.',
|
|
1300
|
+
],
|
|
1301
|
+
activation_required: [exports.LicenseErrorCode.INVALID_LICENSE, '라이선스를 다시 인증해 주세요.'],
|
|
1302
|
+
invalid_instance: [
|
|
1303
|
+
exports.LicenseErrorCode.INVALID_LICENSE,
|
|
1304
|
+
'이 기기의 인증 정보가 만료되었습니다. 다시 인증해 주세요.',
|
|
1305
|
+
],
|
|
1306
|
+
};
|
|
1307
|
+
function normalizeWordPressLicenseResponse(raw, productId) {
|
|
1308
|
+
const data = raw && typeof raw === 'object' ? raw : {};
|
|
1309
|
+
const status = typeof data.status === 'string' ? data.status : 'invalid';
|
|
1310
|
+
if (data.valid !== true || status !== 'active') {
|
|
1311
|
+
const [code, message] = errors[status] || [
|
|
1312
|
+
exports.LicenseErrorCode.INVALID_LICENSE,
|
|
1313
|
+
'유효하지 않은 라이선스 키입니다.',
|
|
1314
|
+
];
|
|
1315
|
+
throw new LicenseCoreError(code, message, undefined, code === exports.LicenseErrorCode.NETWORK_ERROR || code === exports.LicenseErrorCode.RATE_LIMITED);
|
|
1316
|
+
}
|
|
1317
|
+
if (data.product_id !== productId) {
|
|
1318
|
+
throw new LicenseCoreError(exports.LicenseErrorCode.PRODUCT_MISMATCH, '인증 서버의 상품 정보가 일치하지 않습니다.');
|
|
1319
|
+
}
|
|
1320
|
+
const source = typeof data.source === 'string' ? data.source : '';
|
|
1321
|
+
if (data.provider === 'lemon_api' &&
|
|
1322
|
+
(typeof data.instance_id !== 'string' || !data.instance_id)) {
|
|
1323
|
+
throw new LicenseCoreError(exports.LicenseErrorCode.INVALID_LICENSE, '기기 활성화 정보를 확인하지 못했습니다.');
|
|
1324
|
+
}
|
|
1325
|
+
return {
|
|
1326
|
+
valid: true,
|
|
1327
|
+
productId,
|
|
1328
|
+
planTier: 'PAID',
|
|
1329
|
+
licenseStatus: 'active',
|
|
1330
|
+
instanceId: typeof data.instance_id === 'string' ? data.instance_id : undefined,
|
|
1331
|
+
activationLimit: typeof data.activation_limit === 'number' ? data.activation_limit : 0,
|
|
1332
|
+
activationUsage: typeof data.activation_usage === 'number' ? data.activation_usage : 0,
|
|
1333
|
+
licenseSource: source,
|
|
1334
|
+
accessScope: typeof data.access_scope === 'string' ? data.access_scope : 'product',
|
|
1335
|
+
expiresAt: typeof data.expires_at === 'string' ? data.expires_at : undefined,
|
|
1336
|
+
};
|
|
1337
|
+
}
|
|
1338
|
+
function createWordPressLicenseTransport(options) {
|
|
1339
|
+
const { storage, storagePrefix: prefix, productId } = options;
|
|
1340
|
+
if (!productId.trim() || !prefix.trim())
|
|
1341
|
+
throw new Error('productId and storagePrefix are required.');
|
|
1342
|
+
if (!/^https:\/\//i.test(options.baseUrl) &&
|
|
1343
|
+
!/^http:\/\/(localhost|127\.0\.0\.1|\[::1\])(:\d+)?(\/|$)/i.test(options.baseUrl)) {
|
|
1344
|
+
throw new Error('License server must use HTTPS (HTTP is allowed only for local development).');
|
|
1345
|
+
}
|
|
1346
|
+
const timeout = options.timeoutMs || 20000;
|
|
1347
|
+
const fetchFn = options.fetchFn || fetch;
|
|
1348
|
+
const body = (payload) => ({
|
|
1349
|
+
license_key: payload.licenseKey,
|
|
1350
|
+
product_id: productId,
|
|
1351
|
+
instance_id: payload.instanceId || '',
|
|
1352
|
+
device_id: payload.deviceId,
|
|
1353
|
+
});
|
|
1354
|
+
const base = options.baseUrl.replace(/\/$/, '');
|
|
1355
|
+
const http = new FetchLicenseTransport({
|
|
1356
|
+
verifyUrl: `${base}/activate`,
|
|
1357
|
+
validateUrl: `${base}/validate`,
|
|
1358
|
+
deactivateUrl: `${base}/deactivate`,
|
|
1359
|
+
fetchFn,
|
|
1360
|
+
useAbortSignal: false,
|
|
1361
|
+
timeoutMs: timeout,
|
|
1362
|
+
buildVerifyBody: body,
|
|
1363
|
+
buildValidateBody: body,
|
|
1364
|
+
buildDeactivateBody: body,
|
|
1365
|
+
normalizeVerifyResponse: (raw) => normalizeWordPressLicenseResponse(raw, productId),
|
|
1366
|
+
normalizeDeactivateResponse: (raw) => {
|
|
1367
|
+
const data = raw && typeof raw === 'object' ? raw : {};
|
|
1368
|
+
const success = data.success === true || data.deactivated === true;
|
|
1369
|
+
return {
|
|
1370
|
+
success,
|
|
1371
|
+
message: success
|
|
1372
|
+
? undefined
|
|
1373
|
+
: '라이선스 연결을 해제하지 못했습니다. 다시 시도해 주세요.',
|
|
1374
|
+
};
|
|
1375
|
+
},
|
|
1376
|
+
});
|
|
1377
|
+
const enrich = async (payload) => ({
|
|
1378
|
+
...payload,
|
|
1379
|
+
deviceId: await getPersistentLicenseDeviceId(storage, prefix),
|
|
1380
|
+
});
|
|
1381
|
+
return {
|
|
1382
|
+
verify: async (payload) => {
|
|
1383
|
+
const storedKey = await storage.get(`${prefix}:licenseKey`);
|
|
1384
|
+
const storedInstance = await storage.get(`${prefix}:instanceId`);
|
|
1385
|
+
return http.verify(await enrich({
|
|
1386
|
+
...payload,
|
|
1387
|
+
instanceId: payload.instanceId ||
|
|
1388
|
+
(storedKey === payload.licenseKey && typeof storedInstance === 'string'
|
|
1389
|
+
? storedInstance
|
|
1390
|
+
: ''),
|
|
1391
|
+
}));
|
|
1392
|
+
},
|
|
1393
|
+
validate: async (payload) => {
|
|
1394
|
+
const enriched = await enrich(payload);
|
|
1395
|
+
// Legacy users may not have a Lemon instance yet. Activate once;
|
|
1396
|
+
// the server reuses its device mapping when a response was lost.
|
|
1397
|
+
return payload.instanceId ? http.validate(enriched) : http.verify(enriched);
|
|
1398
|
+
},
|
|
1399
|
+
deactivate: async (payload) => http.deactivate(await enrich(payload)),
|
|
1400
|
+
};
|
|
1401
|
+
}
|
|
1402
|
+
|
|
1192
1403
|
class FigmaStorageAdapter {
|
|
1193
1404
|
constructor(figma) {
|
|
1194
1405
|
this.figma = figma;
|
|
@@ -1233,6 +1444,7 @@ const DEFAULT_LICENSE_MESSAGE_TYPES = {
|
|
|
1233
1444
|
class FigmaLicenseStatusManager {
|
|
1234
1445
|
constructor(options) {
|
|
1235
1446
|
this.options = options;
|
|
1447
|
+
this.messageQueue = Promise.resolve();
|
|
1236
1448
|
this.messageTypes = {
|
|
1237
1449
|
...DEFAULT_LICENSE_MESSAGE_TYPES,
|
|
1238
1450
|
...(options.messageTypes || {}),
|
|
@@ -1242,6 +1454,7 @@ class FigmaLicenseStatusManager {
|
|
|
1242
1454
|
async initialize() {
|
|
1243
1455
|
if (!this.initializationPromise) {
|
|
1244
1456
|
this.initializationPromise = (async () => {
|
|
1457
|
+
await this.options.beforeInitialize?.();
|
|
1245
1458
|
const state = await this.options.core.initialize();
|
|
1246
1459
|
await this.postStatusUpdate(state);
|
|
1247
1460
|
})().catch((error) => {
|
|
@@ -1251,7 +1464,12 @@ class FigmaLicenseStatusManager {
|
|
|
1251
1464
|
}
|
|
1252
1465
|
await this.initializationPromise;
|
|
1253
1466
|
}
|
|
1254
|
-
|
|
1467
|
+
handleMessage(pluginMessage) {
|
|
1468
|
+
const operation = this.messageQueue.then(() => this.handleMessageNow(pluginMessage));
|
|
1469
|
+
this.messageQueue = operation.then(() => undefined, () => undefined);
|
|
1470
|
+
return operation;
|
|
1471
|
+
}
|
|
1472
|
+
async handleMessageNow(pluginMessage) {
|
|
1255
1473
|
if (!pluginMessage || typeof pluginMessage !== 'object') {
|
|
1256
1474
|
return false;
|
|
1257
1475
|
}
|
|
@@ -1265,15 +1483,18 @@ class FigmaLicenseStatusManager {
|
|
|
1265
1483
|
return true;
|
|
1266
1484
|
}
|
|
1267
1485
|
if (type === this.messageTypes.verifyLicense) {
|
|
1486
|
+
await this.initialize();
|
|
1268
1487
|
const licenseKey = typeof message.licenseKey === 'string' ? message.licenseKey : '';
|
|
1269
1488
|
await this.handleVerifyLicense(licenseKey);
|
|
1270
1489
|
return true;
|
|
1271
1490
|
}
|
|
1272
1491
|
if (type === this.messageTypes.deactivateLicense) {
|
|
1492
|
+
await this.initialize();
|
|
1273
1493
|
await this.handleDeactivateLicense();
|
|
1274
1494
|
return true;
|
|
1275
1495
|
}
|
|
1276
1496
|
if (type === this.messageTypes.checkFeatureAccess) {
|
|
1497
|
+
await this.initialize();
|
|
1277
1498
|
const featureKey = typeof message.featureKey === 'string' ? message.featureKey : undefined;
|
|
1278
1499
|
const amount = typeof message.amount === 'number' && Number.isFinite(message.amount) && message.amount > 0
|
|
1279
1500
|
? message.amount
|
|
@@ -1282,6 +1503,7 @@ class FigmaLicenseStatusManager {
|
|
|
1282
1503
|
return true;
|
|
1283
1504
|
}
|
|
1284
1505
|
if (type === this.messageTypes.consumeUsage) {
|
|
1506
|
+
await this.initialize();
|
|
1285
1507
|
const amount = typeof message.amount === 'number' && Number.isFinite(message.amount) && message.amount > 0
|
|
1286
1508
|
? message.amount
|
|
1287
1509
|
: 1;
|
|
@@ -1305,6 +1527,7 @@ class FigmaLicenseStatusManager {
|
|
|
1305
1527
|
* This is the preferred guard for operations handled entirely in main.
|
|
1306
1528
|
*/
|
|
1307
1529
|
async canUseFeature(featureKey, amount = 1) {
|
|
1530
|
+
await this.initialize();
|
|
1308
1531
|
const state = await this.options.core.getStatus();
|
|
1309
1532
|
const safeAmount = Number.isFinite(amount) && amount > 0 ? amount : 1;
|
|
1310
1533
|
return this.options.core.resolveUsageAccess(state, featureKey, safeAmount);
|
|
@@ -1313,6 +1536,7 @@ class FigmaLicenseStatusManager {
|
|
|
1313
1536
|
* Consume usage from main code and publish the refreshed status to the UI.
|
|
1314
1537
|
*/
|
|
1315
1538
|
async consumeUsage(amount = 1, featureKey) {
|
|
1539
|
+
await this.initialize();
|
|
1316
1540
|
const result = await this.options.core.consumeUsage(amount, featureKey);
|
|
1317
1541
|
await this.postStatusUpdate(result.state);
|
|
1318
1542
|
return result;
|
|
@@ -1449,14 +1673,21 @@ function createFigmaLicenseStatusManager(options) {
|
|
|
1449
1673
|
const figmaApi = resolveFigmaApi(options.figma);
|
|
1450
1674
|
const storage = options.storage ?? new FigmaStorageAdapter(figmaApi);
|
|
1451
1675
|
const notifier = options.notifier ?? new FigmaNotifierAdapter(figmaApi);
|
|
1452
|
-
const
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1676
|
+
const prefix = options.config.storagePrefix?.trim() || `${options.config.instanceName}:${options.config.productId}`;
|
|
1677
|
+
const transport = options.transport ?? (options.wordpress
|
|
1678
|
+
? createWordPressLicenseTransport({
|
|
1679
|
+
baseUrl: options.wordpress.baseUrl, productId: options.config.productId,
|
|
1680
|
+
storagePrefix: prefix, storage, fetchFn: options.fetchFn,
|
|
1681
|
+
timeoutMs: options.config.requestTimeoutMs,
|
|
1682
|
+
})
|
|
1683
|
+
: new FetchLicenseTransport({
|
|
1684
|
+
verifyUrl: options.config.endpoint,
|
|
1685
|
+
validateUrl: options.config.validateEndpoint,
|
|
1686
|
+
deactivateUrl: options.config.deactivateEndpoint,
|
|
1687
|
+
headers: options.config.requestHeaders,
|
|
1688
|
+
timeoutMs: options.config.requestTimeoutMs,
|
|
1689
|
+
fetchFn: options.fetchFn,
|
|
1690
|
+
}));
|
|
1460
1691
|
const coreDependencies = {
|
|
1461
1692
|
storage,
|
|
1462
1693
|
transport,
|
|
@@ -1468,6 +1699,26 @@ function createFigmaLicenseStatusManager(options) {
|
|
|
1468
1699
|
core,
|
|
1469
1700
|
notifier,
|
|
1470
1701
|
messageTypes: options.messageTypes,
|
|
1702
|
+
beforeInitialize: options.migrateLegacyStorage
|
|
1703
|
+
? () => migrateLegacyLicenseStorage(storage, prefix, typeof options.migrateLegacyStorage === 'object' ? options.migrateLegacyStorage : undefined)
|
|
1704
|
+
: undefined,
|
|
1705
|
+
});
|
|
1706
|
+
}
|
|
1707
|
+
/** Shared membership + Lemon gateway setup. Product allowlists stay on the server. */
|
|
1708
|
+
function createWordPressFigmaLicenseManager(options) {
|
|
1709
|
+
const base = options.serverBaseUrl.replace(/\/$/, '');
|
|
1710
|
+
return createFigmaLicenseStatusManager({
|
|
1711
|
+
figma: options.figma, storage: options.storage, notifier: options.notifier,
|
|
1712
|
+
fetchFn: options.fetchFn, messageTypes: options.messageTypes,
|
|
1713
|
+
migrateLegacyStorage: options.migrateLegacyStorage ?? true,
|
|
1714
|
+
wordpress: { baseUrl: base },
|
|
1715
|
+
config: {
|
|
1716
|
+
productId: options.productId, instanceName: options.instanceName || options.productId,
|
|
1717
|
+
storagePrefix: options.storagePrefix || `designbase:${options.productId}`,
|
|
1718
|
+
endpoint: `${base}/activate`, validateEndpoint: `${base}/validate`, deactivateEndpoint: `${base}/deactivate`,
|
|
1719
|
+
requestTimeoutMs: options.timeoutMs || 20000,
|
|
1720
|
+
policy: options.policy,
|
|
1721
|
+
},
|
|
1471
1722
|
});
|
|
1472
1723
|
}
|
|
1473
1724
|
|
|
@@ -1482,8 +1733,13 @@ exports.LicenseCore = LicenseCore;
|
|
|
1482
1733
|
exports.LicenseCoreError = LicenseCoreError;
|
|
1483
1734
|
exports.LicenseTransportHttpError = LicenseTransportHttpError;
|
|
1484
1735
|
exports.createFigmaLicenseStatusManager = createFigmaLicenseStatusManager;
|
|
1736
|
+
exports.createWordPressFigmaLicenseManager = createWordPressFigmaLicenseManager;
|
|
1737
|
+
exports.createWordPressLicenseTransport = createWordPressLicenseTransport;
|
|
1485
1738
|
exports.defaultNormalizeDeactivateResponse = defaultNormalizeDeactivateResponse;
|
|
1486
1739
|
exports.defaultNormalizeVerifyResponse = defaultNormalizeVerifyResponse;
|
|
1740
|
+
exports.getPersistentLicenseDeviceId = getPersistentLicenseDeviceId;
|
|
1487
1741
|
exports.isActivationLimitReached = isActivationLimitReached;
|
|
1488
1742
|
exports.mapLicenseError = mapLicenseError;
|
|
1743
|
+
exports.migrateLegacyLicenseStorage = migrateLegacyLicenseStorage;
|
|
1744
|
+
exports.normalizeWordPressLicenseResponse = normalizeWordPressLicenseResponse;
|
|
1489
1745
|
//# sourceMappingURL=index.js.map
|