@proveanything/smartlinks 2.0.50 → 2.0.52

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/openapi.yaml CHANGED
@@ -19218,16 +19218,113 @@ components:
19218
19218
  AppDataHandle:
19219
19219
  type: object
19220
19220
  properties: {}
19221
+ AppRecordClaimResult:
19222
+ type: object
19223
+ properties:
19224
+ record:
19225
+ type: object
19226
+ additionalProperties: true
19227
+ created:
19228
+ type: boolean
19229
+ conflict:
19230
+ type: string
19231
+ enum:
19232
+ - singleton
19233
+ - customId
19234
+ required:
19235
+ - record
19236
+ - created
19237
+ ServerFunctionCounters:
19238
+ type: object
19239
+ properties: {}
19240
+ ResolvedTag:
19241
+ type: object
19242
+ properties:
19243
+ id:
19244
+ type: string
19245
+ claimSetId:
19246
+ type: string
19247
+ code:
19248
+ type: string
19249
+ required:
19250
+ - id
19251
+ - claimSetId
19252
+ - code
19253
+ ContactUpsertDetails:
19254
+ type: object
19255
+ properties:
19256
+ email:
19257
+ type: string
19258
+ phone:
19259
+ type: string
19260
+ firstName:
19261
+ type: string
19262
+ lastName:
19263
+ type: string
19264
+ displayName:
19265
+ type: string
19266
+ company:
19267
+ type: string
19268
+ locale:
19269
+ type: string
19270
+ timezone:
19271
+ type: string
19272
+ customFields:
19273
+ type: object
19274
+ additionalProperties:
19275
+ type: object
19276
+ additionalProperties: true
19277
+ ServerFunctionInteractionEvent:
19278
+ type: object
19279
+ properties:
19280
+ interactionId:
19281
+ type: string
19282
+ contactId:
19283
+ type: string
19284
+ outcome:
19285
+ type: string
19286
+ metadata:
19287
+ type: object
19288
+ additionalProperties: true
19289
+ productId:
19290
+ type: string
19291
+ proofId:
19292
+ type: string
19293
+ variantId:
19294
+ type: string
19295
+ batchId:
19296
+ type: string
19297
+ eventType:
19298
+ type: string
19299
+ required:
19300
+ - interactionId
19221
19301
  ServerFunctionSl:
19222
19302
  type: object
19223
19303
  properties:
19224
- appRecords: {}
19304
+ appRecords:
19305
+ type: object
19306
+ additionalProperties: true
19307
+ counters:
19308
+ $ref: "#/components/schemas/ServerFunctionCounters"
19309
+ tags:
19310
+ type: object
19311
+ additionalProperties: true
19312
+ contacts:
19313
+ type: object
19314
+ additionalProperties: true
19315
+ interactions:
19316
+ type: object
19317
+ additionalProperties: true
19225
19318
  products: {}
19226
19319
  attestations: {}
19227
19320
  appData:
19228
19321
  $ref: "#/components/schemas/AppDataHandle"
19229
19322
  required:
19230
19323
  - appRecords
19324
+ - counters
19325
+ - tags
19326
+ - contacts
19327
+ - interactions
19231
19328
  - products
19232
19329
  - attestations
19233
19330
  - appData
@@ -23658,14 +23755,22 @@ components:
23658
23755
  properties:
23659
23756
  email:
23660
23757
  type: string
23758
+ templateId:
23759
+ type: string
23661
23760
  topics:
23662
23761
  type: array
23663
23762
  items:
23664
23763
  type: string
23665
23764
  firstName:
23666
23765
  type: string
23766
+ fields:
23767
+ type: object
23768
+ additionalProperties: true
23769
+ appId:
23770
+ type: string
23667
23771
  required:
23668
23772
  - email
23773
+ - templateId
23669
23774
  CommsSignupResponse:
23670
23775
  type: object
23671
23776
  properties:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@proveanything/smartlinks",
3
- "version": "2.0.50",
3
+ "version": "2.0.52",
4
4
  "description": "Official JavaScript/TypeScript SDK for the Smartlinks API",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -168,16 +168,26 @@ if (meta.cssBaseline) {
168
168
  for (const c of ['sl-mobile-admin']) baseSet.add(c);
169
169
  // Class usage lives in compiled markup strings — present in every bundle regardless
170
170
  // of module format, so scan both umd + esm across all surfaces.
171
+ // `sl-…` NOT preceded by a word char or hyphen: a class name, never a CSS custom property
172
+ // (`var(--sl-color-accent)`, `--sl-widget-accent`) — those are theme tokens, not classes.
173
+ // Classes the app defines itself (`.sl-foo {…}` in its own CSS) aren't missing either.
171
174
  const used = new Set();
175
+ const defined = new Set();
172
176
  for (const [, block] of surfaces) {
173
- for (const p of [block?.files?.js?.umd, block?.files?.js?.esm]) {
174
- if (!p) continue;
177
+ for (const p of [block?.files?.js?.umd, block?.files?.js?.esm, block?.files?.css]) {
178
+ if (!p || typeof p !== 'string') continue;
175
179
  const bp = resolveBundle(p);
176
180
  if (!bp) continue;
177
- for (const m of readFileSync(bp, 'utf8').matchAll(/\bsl-[a-z0-9-]+/g)) used.add(m[0]);
181
+ const text = readFileSync(bp, 'utf8');
182
+ for (const m of text.matchAll(/(?<![\w-])sl-[a-z0-9-]+/g)) used.add(m[0]);
183
+ for (const m of text.matchAll(/\.(sl-[a-z0-9-]+)/g)) defined.add(m[1]);
178
184
  }
179
185
  }
180
- const unknown = [...used].filter((c) => !baseSet.has(c)).sort();
186
+ const ownSl = [...defined].filter((c) => !baseSet.has(c)).sort();
187
+ if (ownSl.length) {
188
+ warnings.push(`the app's own classes use the platform's sl- prefix: ${ownSl.join(', ')} — rename them (e.g. drop the "sl-") so they can't collide with a future baseline class.`);
189
+ }
190
+ const unknown = [...used].filter((c) => !baseSet.has(c) && !defined.has(c)).sort();
181
191
  if (used.size === 0) {
182
192
  console.log(`${DIM}cssBaseline (${baseline.version}) — declared; no sl-* classes found in the bundles.${RESET}`);
183
193
  } else if (unknown.length === 0) {
@@ -238,6 +248,51 @@ if (meta.respectsHostTheme) {
238
248
  }
239
249
  }
240
250
 
251
+ // ---- containers: a router of their own must be isolated from the host's ------------------------
252
+ // Since R5, react-router-dom is SHARED with the host, so a container that wraps itself in a
253
+ // MemoryRouter/HashRouter/BrowserRouter inside the host's router throws "You cannot render a <Router>
254
+ // inside another <Router>" — unless it resets the parent's router context first (docs/containers.md →
255
+ // "Pages that read their context from the URL"). Heuristic on the built bundle names; WARN-only.
256
+ {
257
+ const block = manifest.containers;
258
+ for (const p of [block?.files?.js?.esm, block?.files?.js?.umd]) {
259
+ if (!p) continue;
260
+ const bp = resolveBundle(p);
261
+ if (!bp) continue;
262
+ const text = readFileSync(bp, 'utf8');
263
+ const routers = ['MemoryRouter', 'HashRouter', 'BrowserRouter'].filter((r) => new RegExp(`\\b${r}\\b`).test(text));
264
+ if (!routers.length) { console.log(`${GREEN}✓${RESET} containers ${DIM}— no router of their own (the host's is used)${RESET}`); break; }
265
+ if (/UNSAFE_LocationContext/.test(text)) { console.log(`${GREEN}✓${RESET} containers ${DIM}— own ${routers.join('/')} isolated from the host's router${RESET}`); break; }
266
+ console.log(`${YELLOW}⚠${RESET} containers — ${routers.join('/')} without isolating it from the host's router`);
267
+ warnings.push(`containers bundle renders its own ${routers.join('/')} but never resets the host's router context — inside an R5 host that throws "You cannot render a <Router> inside another <Router>". Wrap it in UNSAFE_LocationContext.Provider + UNSAFE_NavigationContext.Provider value={null} (docs/containers.md), or drop the router and use the host's.`);
268
+ break;
269
+ }
270
+ }
271
+
272
+ // ---- package.json scripts point at files that exist ------------------------------------------
273
+ // An upgrade that copies a script LINE but not the script FILE breaks every build at that step
274
+ // (e.g. `postbuild: node scripts/smartlinks-deploy.mjs` with no scripts/smartlinks-deploy.mjs).
275
+ // WARN — the doctor runs inside the build, and a skipped hook (Forge builds skip pre/post) is harmless.
276
+ try {
277
+ const pkg = JSON.parse(readFileSync(join(appDir, 'package.json'), 'utf8'));
278
+ const missing = [];
279
+ for (const [name, cmd] of Object.entries(pkg.scripts || {})) {
280
+ if (typeof cmd !== 'string') continue;
281
+ for (const m of cmd.matchAll(/(?:^|[;&|]\s*|\s)(?:node|tsx|ts-node|bash|sh)\s+(?:-{1,2}[\w-]+(?:=\S+)?\s+)*((?:\.{1,2}\/)?[\w./-]+\.(?:mjs|cjs|js|ts|sh))\b/g)) {
282
+ if (!existsSync(join(appDir, m[1]))) missing.push(`"${name}" runs ${m[1]}`);
283
+ }
284
+ }
285
+ if (missing.length) {
286
+ console.log(`${YELLOW}⚠${RESET} package.json scripts — ${missing.length} point${missing.length === 1 ? 's' : ''} at a file that doesn't exist:`);
287
+ for (const x of missing) console.log(` ${YELLOW}${x}${RESET}`);
288
+ warnings.push(`package.json ${missing.join('; ')} — but the file is missing. Add the file, or remove the script (a pre/post hook like postbuild fails every \`npm run build\` without it).`);
289
+ } else {
290
+ console.log(`${GREEN}✓${RESET} package.json scripts ${DIM}— every script file they run exists${RESET}`);
291
+ }
292
+ } catch {
293
+ /* no package.json — not an npm app */
294
+ }
295
+
241
296
  console.log('');
242
297
  for (const w of warnings) console.log(`${YELLOW}⚠ ${w}${RESET}`);
243
298