@proveanything/smartlinks 1.15.5 → 1.15.8
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/docs/API_SUMMARY.md +1 -4
- package/dist/docs/appConfig.md +46 -58
- package/dist/openapi.yaml +0 -8
- package/dist/types/appConfiguration.d.ts +0 -1
- package/dist/types/collection.d.ts +0 -2
- package/docs/API_SUMMARY.md +1 -4
- package/docs/appConfig.md +46 -58
- package/openapi.yaml +0 -8
- package/package.json +1 -1
package/dist/docs/API_SUMMARY.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Smartlinks API Summary
|
|
2
2
|
|
|
3
|
-
Version: 1.15.
|
|
3
|
+
Version: 1.15.8 | Generated: 2026-07-19T09:55:23.623Z
|
|
4
4
|
|
|
5
5
|
This is a concise summary of all available API functions and types.
|
|
6
6
|
|
|
@@ -1447,7 +1447,6 @@ interface AppConfigSettings {
|
|
|
1447
1447
|
addOns?: string[]
|
|
1448
1448
|
requestedBasePlanId?: string
|
|
1449
1449
|
itemRecordMode?: 'registered' | 'owned' | null
|
|
1450
|
-
virtualItemsEnabled?: boolean
|
|
1451
1450
|
system?: SystemBlock
|
|
1452
1451
|
}
|
|
1453
1452
|
```
|
|
@@ -3698,8 +3697,6 @@ interface Collection {
|
|
|
3698
3697
|
secondaryColor?: string
|
|
3699
3698
|
portalUrl?: string // URL for the collection's portal (if applicable)
|
|
3700
3699
|
allowAutoGenerateClaims?: boolean
|
|
3701
|
-
variants: boolean // does this collection support variants?
|
|
3702
|
-
batches: boolean // does this collection support batches?
|
|
3703
3700
|
defaultAuthKitId: string // default auth kit for this collection, used for auth
|
|
3704
3701
|
}
|
|
3705
3702
|
```
|
package/dist/docs/appConfig.md
CHANGED
|
@@ -36,7 +36,6 @@ export interface AppConfigSettings {
|
|
|
36
36
|
|
|
37
37
|
/** How the account handles individual physical items. */
|
|
38
38
|
itemRecordMode?: 'registered' | 'owned' | null;
|
|
39
|
-
virtualItemsEnabled?: boolean;
|
|
40
39
|
|
|
41
40
|
// ── SYSTEM-OWNED, PUBLIC (reconcile writes; client read-only) ─────
|
|
42
41
|
/** Resolved entitlement truth. Read this to gate features. */
|
|
@@ -220,26 +219,50 @@ Resolution rule (see `resolveFeature()` / `isFeatureEnabled()`, §6.0):
|
|
|
220
219
|
| `false` (explicit) | **off** | off |
|
|
221
220
|
| absent | **on** (enterprise default) | off (standard default) |
|
|
222
221
|
|
|
223
|
-
This is why reading `cfg.system.features.
|
|
222
|
+
This is why reading `cfg.system.features.customDomain` directly is wrong
|
|
224
223
|
for enterprise accounts — an absent key there does NOT mean disabled:
|
|
225
224
|
|
|
226
225
|
```ts
|
|
227
226
|
// ❌ WRONG for enterprise accounts — absent key silently reads as "off"
|
|
228
|
-
if (cfg.system.features.
|
|
227
|
+
if (cfg.system.features.customDomain) enableCustomDomainUI();
|
|
229
228
|
|
|
230
229
|
// ✅ CORRECT — applies the enterprise default
|
|
231
|
-
if (await appConfiguration.isFeatureEnabled(collectionId, '
|
|
230
|
+
if (await appConfiguration.isFeatureEnabled(collectionId, 'customDomain')) {
|
|
232
231
|
enableCustomDomainUI();
|
|
233
232
|
}
|
|
234
233
|
```
|
|
235
234
|
|
|
236
|
-
Feature flag naming:
|
|
235
|
+
Feature flag naming: camelCase, no `feature`/`is`/`has` prefix (e.g.
|
|
236
|
+
`customDomain`, not `feature_custom_domain` or `isCustomDomainEnabled`).
|
|
237
|
+
Flags belonging to the same topic/module may use a dotted grouping prefix,
|
|
238
|
+
e.g. `crm.broadcasts`, `crm.segments` — this is a plain string key in
|
|
239
|
+
`features`, not a nested object, so resolve it the same way:
|
|
240
|
+
`isFeatureEnabled(collectionId, 'crm.broadcasts')`.
|
|
237
241
|
|
|
238
242
|
Always resolve flags through `appConfiguration.isFeatureEnabled(collectionId, flag)`
|
|
239
243
|
/ `isFeatureEnabledSync()` (§6.0), or `appConfiguration.resolveFeature(cfg.system, flag)`
|
|
240
244
|
if you already have a `system` block from elsewhere — never read
|
|
241
245
|
`cfg.system.features[flag]` directly.
|
|
242
246
|
|
|
247
|
+
#### 4.4.1 Common feature flags
|
|
248
|
+
|
|
249
|
+
`features` is an open map — any microapp can define its own key — but
|
|
250
|
+
these are the major, cross-cutting flags most integrations will care
|
|
251
|
+
about:
|
|
252
|
+
|
|
253
|
+
| Flag | Gates |
|
|
254
|
+
| -------------- | ---------------------------------------------------------------------- |
|
|
255
|
+
| `analytics` | Analytics surfaces (dashboards, reporting, event exploration). |
|
|
256
|
+
| `crm` | Customer interaction / CRM — contact records, broadcasts, segments. Sub-features hang off the `crm.*` dotted prefix, e.g. `crm.broadcasts`, `crm.segments`. |
|
|
257
|
+
| `hub` | The Hub module. |
|
|
258
|
+
| `portal` | QR code scan portals. |
|
|
259
|
+
| `virtualItems` | Virtual items — algorithmic per-item IDs with no persistent row (battery serials, scan-to-collect points, bulk QR sheets). Replaces the old root-level `virtualItemsEnabled` boolean, which has been removed (§8) — resolve this like any other feature flag, not as a separate config key. Independent of `itemRecordMode`. |
|
|
260
|
+
| `batches` | Batch support. Used to be the `Collection.batches` boolean; that field has been removed — this flag is now the only source of truth. |
|
|
261
|
+
| `variants` | Variant support. Used to be the `Collection.variants` boolean; that field has been removed — this flag is now the only source of truth. |
|
|
262
|
+
|
|
263
|
+
Same resolution rule as any flag (§4.4) — don't read these off
|
|
264
|
+
`cfg.system.features` directly, always go through `isFeatureEnabled()`.
|
|
265
|
+
|
|
243
266
|
### 4.5 `meters`
|
|
244
267
|
|
|
245
268
|
Map keyed by add-on key. Apps reporting usage should call the
|
|
@@ -308,7 +331,7 @@ every subsequent call — so calling it once per component, or once per
|
|
|
308
331
|
render, doesn't cause repeat network requests.
|
|
309
332
|
|
|
310
333
|
```ts
|
|
311
|
-
if (await SL.appConfiguration.isFeatureEnabled(collectionId, '
|
|
334
|
+
if (await SL.appConfiguration.isFeatureEnabled(collectionId, 'customDomain')) {
|
|
312
335
|
enableCustomDomainUI();
|
|
313
336
|
}
|
|
314
337
|
```
|
|
@@ -321,11 +344,11 @@ cache once during app init and use the sync variant afterwards:
|
|
|
321
344
|
```ts
|
|
322
345
|
// Once, e.g. in a top-level effect or before first render:
|
|
323
346
|
useEffect(() => {
|
|
324
|
-
SL.appConfiguration.isFeatureEnabled(collectionId, '
|
|
347
|
+
SL.appConfiguration.isFeatureEnabled(collectionId, 'customDomain')
|
|
325
348
|
}, [collectionId]);
|
|
326
349
|
|
|
327
350
|
// Anywhere else, read synchronously — no await:
|
|
328
|
-
const enabled = SL.appConfiguration.isFeatureEnabledSync(collectionId, '
|
|
351
|
+
const enabled = SL.appConfiguration.isFeatureEnabledSync(collectionId, 'customDomain');
|
|
329
352
|
if (enabled === undefined) {
|
|
330
353
|
// not warmed yet this page load — treat as "not yet known", not "off"
|
|
331
354
|
}
|
|
@@ -341,7 +364,7 @@ to bypass it — e.g. immediately after your own code calls
|
|
|
341
364
|
`entitlements-reconcile` and the flags may have changed:
|
|
342
365
|
|
|
343
366
|
```ts
|
|
344
|
-
await SL.appConfiguration.isFeatureEnabled(collectionId, '
|
|
367
|
+
await SL.appConfiguration.isFeatureEnabled(collectionId, 'customDomain', { force: true });
|
|
345
368
|
```
|
|
346
369
|
|
|
347
370
|
### 6.1 Reading the raw config
|
|
@@ -402,18 +425,14 @@ with a stale local copy.
|
|
|
402
425
|
Clients MUST NOT write directly to `system` or `systemPrivate`.
|
|
403
426
|
`entitlements-reconcile` merges user-owned fields through untouched.
|
|
404
427
|
|
|
405
|
-
## 8. Item handling (`itemRecordMode
|
|
428
|
+
## 8. Item handling (`itemRecordMode`)
|
|
406
429
|
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
them.
|
|
430
|
+
A root-level, user-owned key describing how the account treats
|
|
431
|
+
individual physical items. Reconcile never touches it.
|
|
410
432
|
|
|
411
|
-
|
|
433
|
+
Two axes (do NOT conflate):
|
|
412
434
|
|
|
413
|
-
1. **
|
|
414
|
-
IDs, no per-item row. Battery serials, scan-to-collect points,
|
|
415
|
-
bulk QR sheets. Can be on with `itemRecordMode` off.
|
|
416
|
-
2. **Item records** — `itemRecordMode`. Materialise a persistent row
|
|
435
|
+
1. **Item records** — `itemRecordMode`. Materialise a persistent row
|
|
417
436
|
per physical item. `null` / missing = **disabled** (no separate
|
|
418
437
|
`"none"` enum — reads collapse to `mode === "off"` via the
|
|
419
438
|
`useItemRecordMode()` hook).
|
|
@@ -421,7 +440,15 @@ Three axes (do NOT conflate):
|
|
|
421
440
|
provenance without a customer relationship.
|
|
422
441
|
- `"owned"` — tag row + owner + interaction history. Requires
|
|
423
442
|
`basePlanId >= "engage"`. Enables claim / transfer / CRM.
|
|
424
|
-
|
|
443
|
+
2. **CRM** — downstream consequence of `owned`; not a peer flag.
|
|
444
|
+
|
|
445
|
+
**Virtual items are not part of this key.** Algorithmic IDs with no
|
|
446
|
+
per-item row (battery serials, scan-to-collect points, bulk QR sheets)
|
|
447
|
+
used to be a separate root-level `virtualItemsEnabled: boolean` — that
|
|
448
|
+
field has been removed. Virtual items are now gated by the `virtualItems`
|
|
449
|
+
feature flag under `system.features` (§4.4.1), same as every other
|
|
450
|
+
feature — resolve it with `isFeatureEnabled(collectionId, 'virtualItems')`.
|
|
451
|
+
It's independent of `itemRecordMode` and can be on with item records off.
|
|
425
452
|
|
|
426
453
|
**Billing:** the usage ledger stamps `tier` at event time from
|
|
427
454
|
`itemRecordMode`. Writes with `mode === null` MUST be rejected. Mode
|
|
@@ -442,42 +469,3 @@ CRM visibility), not just a capability flag.
|
|
|
442
469
|
features yet.
|
|
443
470
|
- `systemOverrides` (old root-level key) → `systemPrivate.overrides`.
|
|
444
471
|
One-off backfill moves the block and re-runs reconcile.
|
|
445
|
-
|
|
446
|
-
## 10. Change log
|
|
447
|
-
|
|
448
|
-
- **2026-07-17**: Initial contract published; `appConfig.system` becomes
|
|
449
|
-
canonical entitlements source of truth. `entitlements` group deprecated.
|
|
450
|
-
- **2026-07-17**: Added `systemOverrides` for additive comps; reconcile
|
|
451
|
-
records `system.appliedOverrides`.
|
|
452
|
-
- **2026-07-18**: Renamed `systemOverrides` → `systemPrivate.overrides`
|
|
453
|
-
and formalised the three-tier access model (user / system /
|
|
454
|
-
systemPrivate). API strips `systemPrivate` for non-admin readers.
|
|
455
|
-
Added `system.accountType` derived from
|
|
456
|
-
`systemPrivate.overrides.accountType`. Added top-of-doc TypeScript
|
|
457
|
-
definition.
|
|
458
|
-
- **2026-07-18**: Added SDK helpers `appConfiguration.getAppConfig()`
|
|
459
|
-
(typed + cached), `isFeatureEnabled()` (async, cache-backed feature
|
|
460
|
-
gate), and `isFeatureEnabledSync()` (cache-only, for callers that can't
|
|
461
|
-
await). Renamed the exported TypeScript type to `AppConfigSettings`
|
|
462
|
-
to avoid a name collision with the existing per-module `AppConfig`
|
|
463
|
-
type in `src/types/collection.ts`.
|
|
464
|
-
- **2026-07-18**: `/public/collection/:id/app/config` (`collection.getAppsConfig()`)
|
|
465
|
-
now returns the `appConfig` entitlements data (`system`, `addOns`,
|
|
466
|
-
`requestedBasePlanId`, `itemRecordMode`, `virtualItemsEnabled`) merged
|
|
467
|
-
alongside its existing app-catalog `apps[]`. `appConfiguration.getAppConfig()`
|
|
468
|
-
was repointed at this endpoint (dropping its `admin` option — this endpoint
|
|
469
|
-
is public-only); the settings-group endpoint (`appConfiguration.getConfig({ appId: 'appConfig' })`)
|
|
470
|
-
is still the only way to reach `systemPrivate`. See §3.1 for why the two
|
|
471
|
-
endpoints' `apps[]` fields are shaped differently and shouldn't be conflated.
|
|
472
|
-
- **2026-07-18**: `system.features` changed from "only truthy flags appear"
|
|
473
|
-
to explicit `Record<string, boolean>` overrides. Added the `accountType`
|
|
474
|
-
default rule (§4.4): enterprise accounts default every flag to on unless
|
|
475
|
-
explicitly `false`; standard accounts default off unless explicitly `true`.
|
|
476
|
-
Added `appConfiguration.resolveFeature(system, flag)` — the pure resolver
|
|
477
|
-
behind `isFeatureEnabled()`/`isFeatureEnabledSync()`, exposed only for the
|
|
478
|
-
rare case of already holding a `system` block from somewhere other than
|
|
479
|
-
`getAppConfig()`. There is no separate admin feature-check path — `system`
|
|
480
|
-
is public data on every read, so admin surfaces should call
|
|
481
|
-
`isFeatureEnabled()` like everything else. Reading `cfg.system.features[flag]`
|
|
482
|
-
directly is no longer correct for enterprise accounts — always resolve
|
|
483
|
-
through one of these three.
|
package/dist/openapi.yaml
CHANGED
|
@@ -15719,8 +15719,6 @@ components:
|
|
|
15719
15719
|
enum:
|
|
15720
15720
|
- registered
|
|
15721
15721
|
- owned
|
|
15722
|
-
virtualItemsEnabled:
|
|
15723
|
-
type: boolean
|
|
15724
15722
|
system:
|
|
15725
15723
|
$ref: "#/components/schemas/SystemBlock"
|
|
15726
15724
|
required:
|
|
@@ -19309,10 +19307,6 @@ components:
|
|
|
19309
19307
|
type: string
|
|
19310
19308
|
allowAutoGenerateClaims:
|
|
19311
19309
|
type: boolean
|
|
19312
|
-
variants:
|
|
19313
|
-
type: boolean
|
|
19314
|
-
batches:
|
|
19315
|
-
type: boolean
|
|
19316
19310
|
defaultAuthKitId:
|
|
19317
19311
|
type: string
|
|
19318
19312
|
required:
|
|
@@ -19328,8 +19322,6 @@ components:
|
|
|
19328
19322
|
- supported
|
|
19329
19323
|
- roles
|
|
19330
19324
|
- shortId
|
|
19331
|
-
- variants
|
|
19332
|
-
- batches
|
|
19333
19325
|
- defaultAuthKitId
|
|
19334
19326
|
HubAvailabilityResponse:
|
|
19335
19327
|
type: object
|
|
@@ -112,7 +112,6 @@ export interface AppConfigSettings {
|
|
|
112
112
|
requestedBasePlanId?: string;
|
|
113
113
|
/** How the account handles individual physical items. */
|
|
114
114
|
itemRecordMode?: 'registered' | 'owned' | null;
|
|
115
|
-
virtualItemsEnabled?: boolean;
|
|
116
115
|
/** Resolved entitlement truth. Read this to gate features. */
|
|
117
116
|
system?: SystemBlock;
|
|
118
117
|
}
|
|
@@ -57,8 +57,6 @@ export interface Collection {
|
|
|
57
57
|
portalUrl?: string;
|
|
58
58
|
/** Allow users to claim products without providing a proof ID (auto-generates serial on-demand) */
|
|
59
59
|
allowAutoGenerateClaims?: boolean;
|
|
60
|
-
variants: boolean;
|
|
61
|
-
batches: boolean;
|
|
62
60
|
defaultAuthKitId: string;
|
|
63
61
|
}
|
|
64
62
|
export type CollectionResponse = Collection;
|
package/docs/API_SUMMARY.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Smartlinks API Summary
|
|
2
2
|
|
|
3
|
-
Version: 1.15.
|
|
3
|
+
Version: 1.15.8 | Generated: 2026-07-19T09:55:23.623Z
|
|
4
4
|
|
|
5
5
|
This is a concise summary of all available API functions and types.
|
|
6
6
|
|
|
@@ -1447,7 +1447,6 @@ interface AppConfigSettings {
|
|
|
1447
1447
|
addOns?: string[]
|
|
1448
1448
|
requestedBasePlanId?: string
|
|
1449
1449
|
itemRecordMode?: 'registered' | 'owned' | null
|
|
1450
|
-
virtualItemsEnabled?: boolean
|
|
1451
1450
|
system?: SystemBlock
|
|
1452
1451
|
}
|
|
1453
1452
|
```
|
|
@@ -3698,8 +3697,6 @@ interface Collection {
|
|
|
3698
3697
|
secondaryColor?: string
|
|
3699
3698
|
portalUrl?: string // URL for the collection's portal (if applicable)
|
|
3700
3699
|
allowAutoGenerateClaims?: boolean
|
|
3701
|
-
variants: boolean // does this collection support variants?
|
|
3702
|
-
batches: boolean // does this collection support batches?
|
|
3703
3700
|
defaultAuthKitId: string // default auth kit for this collection, used for auth
|
|
3704
3701
|
}
|
|
3705
3702
|
```
|
package/docs/appConfig.md
CHANGED
|
@@ -36,7 +36,6 @@ export interface AppConfigSettings {
|
|
|
36
36
|
|
|
37
37
|
/** How the account handles individual physical items. */
|
|
38
38
|
itemRecordMode?: 'registered' | 'owned' | null;
|
|
39
|
-
virtualItemsEnabled?: boolean;
|
|
40
39
|
|
|
41
40
|
// ── SYSTEM-OWNED, PUBLIC (reconcile writes; client read-only) ─────
|
|
42
41
|
/** Resolved entitlement truth. Read this to gate features. */
|
|
@@ -220,26 +219,50 @@ Resolution rule (see `resolveFeature()` / `isFeatureEnabled()`, §6.0):
|
|
|
220
219
|
| `false` (explicit) | **off** | off |
|
|
221
220
|
| absent | **on** (enterprise default) | off (standard default) |
|
|
222
221
|
|
|
223
|
-
This is why reading `cfg.system.features.
|
|
222
|
+
This is why reading `cfg.system.features.customDomain` directly is wrong
|
|
224
223
|
for enterprise accounts — an absent key there does NOT mean disabled:
|
|
225
224
|
|
|
226
225
|
```ts
|
|
227
226
|
// ❌ WRONG for enterprise accounts — absent key silently reads as "off"
|
|
228
|
-
if (cfg.system.features.
|
|
227
|
+
if (cfg.system.features.customDomain) enableCustomDomainUI();
|
|
229
228
|
|
|
230
229
|
// ✅ CORRECT — applies the enterprise default
|
|
231
|
-
if (await appConfiguration.isFeatureEnabled(collectionId, '
|
|
230
|
+
if (await appConfiguration.isFeatureEnabled(collectionId, 'customDomain')) {
|
|
232
231
|
enableCustomDomainUI();
|
|
233
232
|
}
|
|
234
233
|
```
|
|
235
234
|
|
|
236
|
-
Feature flag naming:
|
|
235
|
+
Feature flag naming: camelCase, no `feature`/`is`/`has` prefix (e.g.
|
|
236
|
+
`customDomain`, not `feature_custom_domain` or `isCustomDomainEnabled`).
|
|
237
|
+
Flags belonging to the same topic/module may use a dotted grouping prefix,
|
|
238
|
+
e.g. `crm.broadcasts`, `crm.segments` — this is a plain string key in
|
|
239
|
+
`features`, not a nested object, so resolve it the same way:
|
|
240
|
+
`isFeatureEnabled(collectionId, 'crm.broadcasts')`.
|
|
237
241
|
|
|
238
242
|
Always resolve flags through `appConfiguration.isFeatureEnabled(collectionId, flag)`
|
|
239
243
|
/ `isFeatureEnabledSync()` (§6.0), or `appConfiguration.resolveFeature(cfg.system, flag)`
|
|
240
244
|
if you already have a `system` block from elsewhere — never read
|
|
241
245
|
`cfg.system.features[flag]` directly.
|
|
242
246
|
|
|
247
|
+
#### 4.4.1 Common feature flags
|
|
248
|
+
|
|
249
|
+
`features` is an open map — any microapp can define its own key — but
|
|
250
|
+
these are the major, cross-cutting flags most integrations will care
|
|
251
|
+
about:
|
|
252
|
+
|
|
253
|
+
| Flag | Gates |
|
|
254
|
+
| -------------- | ---------------------------------------------------------------------- |
|
|
255
|
+
| `analytics` | Analytics surfaces (dashboards, reporting, event exploration). |
|
|
256
|
+
| `crm` | Customer interaction / CRM — contact records, broadcasts, segments. Sub-features hang off the `crm.*` dotted prefix, e.g. `crm.broadcasts`, `crm.segments`. |
|
|
257
|
+
| `hub` | The Hub module. |
|
|
258
|
+
| `portal` | QR code scan portals. |
|
|
259
|
+
| `virtualItems` | Virtual items — algorithmic per-item IDs with no persistent row (battery serials, scan-to-collect points, bulk QR sheets). Replaces the old root-level `virtualItemsEnabled` boolean, which has been removed (§8) — resolve this like any other feature flag, not as a separate config key. Independent of `itemRecordMode`. |
|
|
260
|
+
| `batches` | Batch support. Used to be the `Collection.batches` boolean; that field has been removed — this flag is now the only source of truth. |
|
|
261
|
+
| `variants` | Variant support. Used to be the `Collection.variants` boolean; that field has been removed — this flag is now the only source of truth. |
|
|
262
|
+
|
|
263
|
+
Same resolution rule as any flag (§4.4) — don't read these off
|
|
264
|
+
`cfg.system.features` directly, always go through `isFeatureEnabled()`.
|
|
265
|
+
|
|
243
266
|
### 4.5 `meters`
|
|
244
267
|
|
|
245
268
|
Map keyed by add-on key. Apps reporting usage should call the
|
|
@@ -308,7 +331,7 @@ every subsequent call — so calling it once per component, or once per
|
|
|
308
331
|
render, doesn't cause repeat network requests.
|
|
309
332
|
|
|
310
333
|
```ts
|
|
311
|
-
if (await SL.appConfiguration.isFeatureEnabled(collectionId, '
|
|
334
|
+
if (await SL.appConfiguration.isFeatureEnabled(collectionId, 'customDomain')) {
|
|
312
335
|
enableCustomDomainUI();
|
|
313
336
|
}
|
|
314
337
|
```
|
|
@@ -321,11 +344,11 @@ cache once during app init and use the sync variant afterwards:
|
|
|
321
344
|
```ts
|
|
322
345
|
// Once, e.g. in a top-level effect or before first render:
|
|
323
346
|
useEffect(() => {
|
|
324
|
-
SL.appConfiguration.isFeatureEnabled(collectionId, '
|
|
347
|
+
SL.appConfiguration.isFeatureEnabled(collectionId, 'customDomain')
|
|
325
348
|
}, [collectionId]);
|
|
326
349
|
|
|
327
350
|
// Anywhere else, read synchronously — no await:
|
|
328
|
-
const enabled = SL.appConfiguration.isFeatureEnabledSync(collectionId, '
|
|
351
|
+
const enabled = SL.appConfiguration.isFeatureEnabledSync(collectionId, 'customDomain');
|
|
329
352
|
if (enabled === undefined) {
|
|
330
353
|
// not warmed yet this page load — treat as "not yet known", not "off"
|
|
331
354
|
}
|
|
@@ -341,7 +364,7 @@ to bypass it — e.g. immediately after your own code calls
|
|
|
341
364
|
`entitlements-reconcile` and the flags may have changed:
|
|
342
365
|
|
|
343
366
|
```ts
|
|
344
|
-
await SL.appConfiguration.isFeatureEnabled(collectionId, '
|
|
367
|
+
await SL.appConfiguration.isFeatureEnabled(collectionId, 'customDomain', { force: true });
|
|
345
368
|
```
|
|
346
369
|
|
|
347
370
|
### 6.1 Reading the raw config
|
|
@@ -402,18 +425,14 @@ with a stale local copy.
|
|
|
402
425
|
Clients MUST NOT write directly to `system` or `systemPrivate`.
|
|
403
426
|
`entitlements-reconcile` merges user-owned fields through untouched.
|
|
404
427
|
|
|
405
|
-
## 8. Item handling (`itemRecordMode
|
|
428
|
+
## 8. Item handling (`itemRecordMode`)
|
|
406
429
|
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
them.
|
|
430
|
+
A root-level, user-owned key describing how the account treats
|
|
431
|
+
individual physical items. Reconcile never touches it.
|
|
410
432
|
|
|
411
|
-
|
|
433
|
+
Two axes (do NOT conflate):
|
|
412
434
|
|
|
413
|
-
1. **
|
|
414
|
-
IDs, no per-item row. Battery serials, scan-to-collect points,
|
|
415
|
-
bulk QR sheets. Can be on with `itemRecordMode` off.
|
|
416
|
-
2. **Item records** — `itemRecordMode`. Materialise a persistent row
|
|
435
|
+
1. **Item records** — `itemRecordMode`. Materialise a persistent row
|
|
417
436
|
per physical item. `null` / missing = **disabled** (no separate
|
|
418
437
|
`"none"` enum — reads collapse to `mode === "off"` via the
|
|
419
438
|
`useItemRecordMode()` hook).
|
|
@@ -421,7 +440,15 @@ Three axes (do NOT conflate):
|
|
|
421
440
|
provenance without a customer relationship.
|
|
422
441
|
- `"owned"` — tag row + owner + interaction history. Requires
|
|
423
442
|
`basePlanId >= "engage"`. Enables claim / transfer / CRM.
|
|
424
|
-
|
|
443
|
+
2. **CRM** — downstream consequence of `owned`; not a peer flag.
|
|
444
|
+
|
|
445
|
+
**Virtual items are not part of this key.** Algorithmic IDs with no
|
|
446
|
+
per-item row (battery serials, scan-to-collect points, bulk QR sheets)
|
|
447
|
+
used to be a separate root-level `virtualItemsEnabled: boolean` — that
|
|
448
|
+
field has been removed. Virtual items are now gated by the `virtualItems`
|
|
449
|
+
feature flag under `system.features` (§4.4.1), same as every other
|
|
450
|
+
feature — resolve it with `isFeatureEnabled(collectionId, 'virtualItems')`.
|
|
451
|
+
It's independent of `itemRecordMode` and can be on with item records off.
|
|
425
452
|
|
|
426
453
|
**Billing:** the usage ledger stamps `tier` at event time from
|
|
427
454
|
`itemRecordMode`. Writes with `mode === null` MUST be rejected. Mode
|
|
@@ -442,42 +469,3 @@ CRM visibility), not just a capability flag.
|
|
|
442
469
|
features yet.
|
|
443
470
|
- `systemOverrides` (old root-level key) → `systemPrivate.overrides`.
|
|
444
471
|
One-off backfill moves the block and re-runs reconcile.
|
|
445
|
-
|
|
446
|
-
## 10. Change log
|
|
447
|
-
|
|
448
|
-
- **2026-07-17**: Initial contract published; `appConfig.system` becomes
|
|
449
|
-
canonical entitlements source of truth. `entitlements` group deprecated.
|
|
450
|
-
- **2026-07-17**: Added `systemOverrides` for additive comps; reconcile
|
|
451
|
-
records `system.appliedOverrides`.
|
|
452
|
-
- **2026-07-18**: Renamed `systemOverrides` → `systemPrivate.overrides`
|
|
453
|
-
and formalised the three-tier access model (user / system /
|
|
454
|
-
systemPrivate). API strips `systemPrivate` for non-admin readers.
|
|
455
|
-
Added `system.accountType` derived from
|
|
456
|
-
`systemPrivate.overrides.accountType`. Added top-of-doc TypeScript
|
|
457
|
-
definition.
|
|
458
|
-
- **2026-07-18**: Added SDK helpers `appConfiguration.getAppConfig()`
|
|
459
|
-
(typed + cached), `isFeatureEnabled()` (async, cache-backed feature
|
|
460
|
-
gate), and `isFeatureEnabledSync()` (cache-only, for callers that can't
|
|
461
|
-
await). Renamed the exported TypeScript type to `AppConfigSettings`
|
|
462
|
-
to avoid a name collision with the existing per-module `AppConfig`
|
|
463
|
-
type in `src/types/collection.ts`.
|
|
464
|
-
- **2026-07-18**: `/public/collection/:id/app/config` (`collection.getAppsConfig()`)
|
|
465
|
-
now returns the `appConfig` entitlements data (`system`, `addOns`,
|
|
466
|
-
`requestedBasePlanId`, `itemRecordMode`, `virtualItemsEnabled`) merged
|
|
467
|
-
alongside its existing app-catalog `apps[]`. `appConfiguration.getAppConfig()`
|
|
468
|
-
was repointed at this endpoint (dropping its `admin` option — this endpoint
|
|
469
|
-
is public-only); the settings-group endpoint (`appConfiguration.getConfig({ appId: 'appConfig' })`)
|
|
470
|
-
is still the only way to reach `systemPrivate`. See §3.1 for why the two
|
|
471
|
-
endpoints' `apps[]` fields are shaped differently and shouldn't be conflated.
|
|
472
|
-
- **2026-07-18**: `system.features` changed from "only truthy flags appear"
|
|
473
|
-
to explicit `Record<string, boolean>` overrides. Added the `accountType`
|
|
474
|
-
default rule (§4.4): enterprise accounts default every flag to on unless
|
|
475
|
-
explicitly `false`; standard accounts default off unless explicitly `true`.
|
|
476
|
-
Added `appConfiguration.resolveFeature(system, flag)` — the pure resolver
|
|
477
|
-
behind `isFeatureEnabled()`/`isFeatureEnabledSync()`, exposed only for the
|
|
478
|
-
rare case of already holding a `system` block from somewhere other than
|
|
479
|
-
`getAppConfig()`. There is no separate admin feature-check path — `system`
|
|
480
|
-
is public data on every read, so admin surfaces should call
|
|
481
|
-
`isFeatureEnabled()` like everything else. Reading `cfg.system.features[flag]`
|
|
482
|
-
directly is no longer correct for enterprise accounts — always resolve
|
|
483
|
-
through one of these three.
|
package/openapi.yaml
CHANGED
|
@@ -15719,8 +15719,6 @@ components:
|
|
|
15719
15719
|
enum:
|
|
15720
15720
|
- registered
|
|
15721
15721
|
- owned
|
|
15722
|
-
virtualItemsEnabled:
|
|
15723
|
-
type: boolean
|
|
15724
15722
|
system:
|
|
15725
15723
|
$ref: "#/components/schemas/SystemBlock"
|
|
15726
15724
|
required:
|
|
@@ -19309,10 +19307,6 @@ components:
|
|
|
19309
19307
|
type: string
|
|
19310
19308
|
allowAutoGenerateClaims:
|
|
19311
19309
|
type: boolean
|
|
19312
|
-
variants:
|
|
19313
|
-
type: boolean
|
|
19314
|
-
batches:
|
|
19315
|
-
type: boolean
|
|
19316
19310
|
defaultAuthKitId:
|
|
19317
19311
|
type: string
|
|
19318
19312
|
required:
|
|
@@ -19328,8 +19322,6 @@ components:
|
|
|
19328
19322
|
- supported
|
|
19329
19323
|
- roles
|
|
19330
19324
|
- shortId
|
|
19331
|
-
- variants
|
|
19332
|
-
- batches
|
|
19333
19325
|
- defaultAuthKitId
|
|
19334
19326
|
HubAvailabilityResponse:
|
|
19335
19327
|
type: object
|