@proveanything/smartlinks 2.0.0-alpha.1 → 2.0.0-alpha.2

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.
@@ -1,6 +1,6 @@
1
1
  # Smartlinks API Summary
2
2
 
3
- Version: 2.0.0-alpha.1 | Generated: 2026-09-14T11:30:24.015Z
3
+ Version: 2.0.0-alpha.2 | Generated: 2026-09-14T14:13:56.533Z
4
4
 
5
5
  This is a concise summary of all available API functions and types.
6
6
 
@@ -20,20 +20,30 @@ This guide covers registration and how to wire it into your build.
20
20
 
21
21
  Deploying touches two different locations — keep them distinct:
22
22
 
23
- 1. **The install endpoint (API host)** — *where you register*. This is a SmartLinks
24
- **API v1** endpoint, and its **host is the environment** you're installing into (see
25
- below). This is the one that varies per deployment.
26
- 2. **The bundle CDN** *where your files are served from*. **Today always `smartlinks.app`**:
23
+ 1. **The install endpoint (API host)** — *where you register*. On the **main SaaS this is
24
+ `https://smartlinks.app`** (the API lives under `/api/v1` the same base your app already
25
+ passes to `initializeApi`). A client's isolated (VPC) environment has its **own** host; you
26
+ install into it by calling that host. This is the value that varies per deployment.
27
+ 2. **The bundle CDN** — *where your built files are actually served from*, which you pass at
28
+ registration as **`bundleBaseUrl`**. **This depends on the channel:**
29
+ - **`dev` (Lovable):** your files are served by **Lovable at your published app URL** — that
30
+ URL is your dev `bundleBaseUrl`. Lovable *is* the CDN for dev; nothing is uploaded to
31
+ SmartLinks.
32
+ - **`prod`:** files are published to the SmartLinks app CDN at
33
+ `https://smartlinks.app/apps/{appId}/{version}/…` by your prod deploy step; that base is
34
+ your prod `bundleBaseUrl`.
27
35
 
28
36
  ```
29
- https://smartlinks.app/apps/{appId}/{version}/app.manifest.json
30
- https://smartlinks.app/apps/{appId}/{version}/widgets-<hash>.umd.js
37
+ https://smartlinks.app/apps/{appId}/{version}/app.manifest.json # prod layout
31
38
  https://smartlinks.app/apps/{appId}/{version}/functions.umd.js
32
39
  ```
33
40
 
34
- That base `https://smartlinks.app/apps/{appId}/{version}` is your **`bundleBaseUrl`**,
35
- which you pass at registration. Always pass it explicitly so nothing breaks if the CDN
36
- location changes later.
41
+ Always pass `bundleBaseUrl` explicitly so it keeps working if a location changes.
42
+
43
+ > **Who publishes the bundles?** The platform does **not** fetch or mirror them for you —
44
+ > `bundleBaseUrl` must already serve the files at registration time. For `dev` that's Lovable
45
+ > (on Publish); for `prod` that's your own CDN deploy step. Registration records *where* the
46
+ > bundles are + the validated manifest; it does not host anything.
37
47
 
38
48
  ## Environments & the app registry
39
49
 
@@ -72,26 +82,36 @@ and exercise a build before it reaches `prod`.
72
82
 
73
83
  ## Deploy keys
74
84
 
75
- Registration is authenticated by a **deploy key** — not a user login — scoped to the
76
- channels it may write. Security comes from the *scope*, so a key that leaks can only affect
77
- what it was allowed to touch.
85
+ Registration is authenticated by a **deploy key** — not a user login — scoped to the channels
86
+ it may write. Security comes from the *scope*: a leaked key can only do what its scope allows.
78
87
 
79
- | Key | Lives in | May write |
80
- |---|---|---|
81
- | **Dev key** | your app's (private) source / build env | `dev` channel only |
82
- | **Prod master key** | your Cloud Build toolset only — never in app source | all channels |
83
- | **Per-app key** *(future)* | a client's build | one specific app |
88
+ | Key | Where to keep it | May write | If it leaks |
89
+ |---|---|---|---|
90
+ | **Dev key** | a **Lovable workspace Build Secret** (below) | `dev` channel, **any app in the environment** | someone can register/overwrite `dev` releases — which are served only to test collections — but **never** `beta`/`prod` |
91
+ | **Prod master key** | your CI/Cloud Build secret store **only** | all channels | full control so keep it out of app source entirely |
92
+ | **Per-app key** *(future)* | provisioned per app | one specific app | scoped to that one app |
93
+
94
+ **Keep the dev key in Lovable Build Secrets — do not commit it.** Lovable exposes
95
+ **workspace-level Build Secrets** shared across every project in the workspace: set the dev key
96
+ there **once** and every microapp inherits it, nothing is committed, and there's a single value
97
+ to rotate. (An earlier draft of this guide said to put the key in app source — don't; use Build
98
+ Secrets.)
84
99
 
85
- Because a Lovable build has no secret store, the **dev key lives in your app source** — which
86
- is safe precisely because it can only ever write the `dev` channel. The **prod key stays in
87
- Cloud Build**. Present the key in the `x-smartlinks-deploy-key` header.
100
+ **Minting (current state, 2.0.0-alpha):** the `dev` and `prod` keys are **shared secrets
101
+ configured on the SmartLinks backend** one `dev` key and one `prod` key covering all
102
+ first-party apps. There is **no self-service minting UI yet**: ask the platform owner for the
103
+ `dev` key and put it in your workspace Build Secret. Per-app keys, self-service minting, and
104
+ rotation are planned; rotating the shared `dev` key just means updating the one Build Secret
105
+ (registered releases are unaffected — the key authorizes *writes*, it isn't stored on releases).
106
+
107
+ Present the key in the `x-smartlinks-deploy-key` header.
88
108
 
89
109
  ---
90
110
 
91
111
  ## The registration endpoint
92
112
 
93
113
  ```
94
- POST https://<smartlinks-api>/api/v1/apps/{appId}/releases
114
+ POST https://smartlinks.app/api/v1/apps/{appId}/releases # main SaaS; a VPC env uses its own host
95
115
  x-smartlinks-deploy-key: <your deploy key>
96
116
  Content-Type: application/json
97
117
  ```
@@ -124,6 +144,15 @@ Each validation error is `{ code, message, path }`, e.g.:
124
144
  ]}
125
145
  ```
126
146
 
147
+ ### Re-registering & version collisions
148
+
149
+ Registration is an **upsert keyed by (app, channel)** — the newest registration becomes that
150
+ channel's live release. Registering again **overwrites** it (last write wins); there is **no**
151
+ version-collision error even if `meta.version` is unchanged. So re-publishing to `dev` without
152
+ bumping the version is a normal, intentional overwrite — which is what you want on `dev`. (A
153
+ stricter `prod` policy that rejects a duplicate `version` may come later; it isn't enforced
154
+ today.)
155
+
127
156
  ### What gets validated
128
157
 
129
158
  - `manifest.meta.appId` must match the `{appId}` in the URL.
@@ -145,24 +174,36 @@ so a bad install fails the publish.
145
174
  import { readFileSync } from 'node:fs'
146
175
  import { execSync } from 'node:child_process'
147
176
 
148
- const API = process.env.SMARTLINKS_API || 'https://api.smartlinks.app'
149
- const KEY = process.env.SMARTLINKS_DEPLOY_KEY // dev key (in source/env) or prod key (Cloud Build)
150
- const CHANNEL = process.env.SMARTLINKS_CHANNEL || 'dev' // 'prod' in Cloud Build
177
+ const API = process.env.SMARTLINKS_API || 'https://smartlinks.app' // a VPC env: set to its host
178
+ const KEY = process.env.SMARTLINKS_DEPLOY_KEY // Lovable Build Secret (dev) / CI secret (prod)
179
+ const CHANNEL = process.env.SMARTLINKS_CHANNEL // 'dev' | 'beta' | 'prod'; UNSET don't register
180
+
181
+ // --- Gate: only register when this build is meant to ---
182
+ // A preview / live-edit build (no channel) skips quietly so it never fails. A build that
183
+ // declares a channel but has no key is a hard error IF it's prod; dev skips quietly.
184
+ if (!CHANNEL) {
185
+ console.log('ℹ︎ SmartLinks: SMARTLINKS_CHANNEL unset — skipping release registration (preview build).')
186
+ process.exit(0)
187
+ }
188
+ if (!KEY) {
189
+ if (CHANNEL === 'prod') { console.error('❌ prod build but SMARTLINKS_DEPLOY_KEY is missing'); process.exit(1) }
190
+ console.log(`ℹ︎ SmartLinks: no deploy key for "${CHANNEL}" — skipping registration.`)
191
+ process.exit(0)
192
+ }
151
193
 
152
194
  const manifest = JSON.parse(readFileSync('dist/app.manifest.json', 'utf8'))
153
195
  const appId = manifest.meta.appId
154
196
  const version = manifest.meta.version
155
197
  const gitHash = (() => { try { return execSync('git rev-parse --short HEAD').toString().trim() } catch { return null } })()
198
+ // dev: your published Lovable URL; prod: the SmartLinks CDN base. Set SMARTLINKS_BUNDLE_BASE_URL.
199
+ const bundleBaseUrl = process.env.SMARTLINKS_BUNDLE_BASE_URL || `https://smartlinks.app/apps/${appId}/${version}`
156
200
 
157
201
  const res = await fetch(`${API}/api/v1/apps/${appId}/releases`, {
158
202
  method: 'POST',
159
203
  headers: { 'content-type': 'application/json', 'x-smartlinks-deploy-key': KEY },
160
204
  body: JSON.stringify({
161
- channel: CHANNEL,
162
- version,
163
- build: { at: new Date().toISOString(), gitHash, builder: CHANNEL === 'dev' ? 'lovable' : 'cloudbuild' },
164
- manifest,
165
- bundleBaseUrl: `https://smartlinks.app/apps/${appId}/${version}`,
205
+ channel: CHANNEL, version, manifest, bundleBaseUrl,
206
+ build: { at: new Date().toISOString(), gitHash, builder: CHANNEL === 'dev' ? 'lovable' : 'ci' },
166
207
  }),
167
208
  })
168
209
 
@@ -175,7 +216,7 @@ if (!res.ok || !body.ok) {
175
216
  console.log(`✅ Registered ${appId}@${version} on "${CHANNEL}" — functions: ${(body.functions || []).join(', ') || 'none'}`)
176
217
  ```
177
218
 
178
- Wire it after your bundle build/hash step, e.g.:
219
+ Wire it after your bundle build/hash step:
179
220
 
180
221
  ```jsonc
181
222
  // package.json
@@ -185,9 +226,19 @@ Wire it after your bundle build/hash step, e.g.:
185
226
  }
186
227
  ```
187
228
 
188
- - **Dev (Lovable "Publish")** runs `build` `postbuild` with the **dev key** and
189
- `SMARTLINKS_CHANNEL=dev`.
190
- - **Prod (Cloud Build)** runs the same with the **prod key** and `SMARTLINKS_CHANNEL=prod`.
229
+ Registration is gated by **`SMARTLINKS_CHANNEL`**, so the three Lovable build types behave correctly:
191
230
 
192
- That's it: hitting Publish now validates and registers your app — and a broken manifest or
193
- function stops the deploy with an actionable error instead of shipping.
231
+ | Build | `SMARTLINKS_CHANNEL` | Result |
232
+ |---|---|---|
233
+ | **Preview / live-edit** | unset | **skips quietly** — never registers, never fails |
234
+ | **Dev (Publish)** | `dev` | registers to `dev` with the workspace Build-Secret key + your Lovable `SMARTLINKS_BUNDLE_BASE_URL` |
235
+ | **Prod (CI)** | `prod` | registers to `prod` with the prod key; a missing key **hard-fails** |
236
+
237
+ The gate is `SMARTLINKS_CHANNEL`, so **set it only where you want a release** — i.e. on the
238
+ Publish/CI build, not on preview. If your host exposes a publish-only signal (an env var it sets
239
+ only on Publish), key `SMARTLINKS_CHANNEL` off that; otherwise set it in the Publish build's env
240
+ and leave it unset for preview. That one variable is the difference between "this build ships a
241
+ release" and "this build is just a preview."
242
+
243
+ That's it: a real Publish validates + registers your app (a broken manifest or function stops
244
+ the deploy with an actionable error), while preview builds stay quiet.
@@ -1,6 +1,6 @@
1
1
  # Smartlinks API Summary
2
2
 
3
- Version: 2.0.0-alpha.1 | Generated: 2026-09-14T11:30:24.015Z
3
+ Version: 2.0.0-alpha.2 | Generated: 2026-09-14T14:13:56.533Z
4
4
 
5
5
  This is a concise summary of all available API functions and types.
6
6
 
@@ -20,20 +20,30 @@ This guide covers registration and how to wire it into your build.
20
20
 
21
21
  Deploying touches two different locations — keep them distinct:
22
22
 
23
- 1. **The install endpoint (API host)** — *where you register*. This is a SmartLinks
24
- **API v1** endpoint, and its **host is the environment** you're installing into (see
25
- below). This is the one that varies per deployment.
26
- 2. **The bundle CDN** *where your files are served from*. **Today always `smartlinks.app`**:
23
+ 1. **The install endpoint (API host)** — *where you register*. On the **main SaaS this is
24
+ `https://smartlinks.app`** (the API lives under `/api/v1` the same base your app already
25
+ passes to `initializeApi`). A client's isolated (VPC) environment has its **own** host; you
26
+ install into it by calling that host. This is the value that varies per deployment.
27
+ 2. **The bundle CDN** — *where your built files are actually served from*, which you pass at
28
+ registration as **`bundleBaseUrl`**. **This depends on the channel:**
29
+ - **`dev` (Lovable):** your files are served by **Lovable at your published app URL** — that
30
+ URL is your dev `bundleBaseUrl`. Lovable *is* the CDN for dev; nothing is uploaded to
31
+ SmartLinks.
32
+ - **`prod`:** files are published to the SmartLinks app CDN at
33
+ `https://smartlinks.app/apps/{appId}/{version}/…` by your prod deploy step; that base is
34
+ your prod `bundleBaseUrl`.
27
35
 
28
36
  ```
29
- https://smartlinks.app/apps/{appId}/{version}/app.manifest.json
30
- https://smartlinks.app/apps/{appId}/{version}/widgets-<hash>.umd.js
37
+ https://smartlinks.app/apps/{appId}/{version}/app.manifest.json # prod layout
31
38
  https://smartlinks.app/apps/{appId}/{version}/functions.umd.js
32
39
  ```
33
40
 
34
- That base `https://smartlinks.app/apps/{appId}/{version}` is your **`bundleBaseUrl`**,
35
- which you pass at registration. Always pass it explicitly so nothing breaks if the CDN
36
- location changes later.
41
+ Always pass `bundleBaseUrl` explicitly so it keeps working if a location changes.
42
+
43
+ > **Who publishes the bundles?** The platform does **not** fetch or mirror them for you —
44
+ > `bundleBaseUrl` must already serve the files at registration time. For `dev` that's Lovable
45
+ > (on Publish); for `prod` that's your own CDN deploy step. Registration records *where* the
46
+ > bundles are + the validated manifest; it does not host anything.
37
47
 
38
48
  ## Environments & the app registry
39
49
 
@@ -72,26 +82,36 @@ and exercise a build before it reaches `prod`.
72
82
 
73
83
  ## Deploy keys
74
84
 
75
- Registration is authenticated by a **deploy key** — not a user login — scoped to the
76
- channels it may write. Security comes from the *scope*, so a key that leaks can only affect
77
- what it was allowed to touch.
85
+ Registration is authenticated by a **deploy key** — not a user login — scoped to the channels
86
+ it may write. Security comes from the *scope*: a leaked key can only do what its scope allows.
78
87
 
79
- | Key | Lives in | May write |
80
- |---|---|---|
81
- | **Dev key** | your app's (private) source / build env | `dev` channel only |
82
- | **Prod master key** | your Cloud Build toolset only — never in app source | all channels |
83
- | **Per-app key** *(future)* | a client's build | one specific app |
88
+ | Key | Where to keep it | May write | If it leaks |
89
+ |---|---|---|---|
90
+ | **Dev key** | a **Lovable workspace Build Secret** (below) | `dev` channel, **any app in the environment** | someone can register/overwrite `dev` releases — which are served only to test collections — but **never** `beta`/`prod` |
91
+ | **Prod master key** | your CI/Cloud Build secret store **only** | all channels | full control so keep it out of app source entirely |
92
+ | **Per-app key** *(future)* | provisioned per app | one specific app | scoped to that one app |
93
+
94
+ **Keep the dev key in Lovable Build Secrets — do not commit it.** Lovable exposes
95
+ **workspace-level Build Secrets** shared across every project in the workspace: set the dev key
96
+ there **once** and every microapp inherits it, nothing is committed, and there's a single value
97
+ to rotate. (An earlier draft of this guide said to put the key in app source — don't; use Build
98
+ Secrets.)
84
99
 
85
- Because a Lovable build has no secret store, the **dev key lives in your app source** — which
86
- is safe precisely because it can only ever write the `dev` channel. The **prod key stays in
87
- Cloud Build**. Present the key in the `x-smartlinks-deploy-key` header.
100
+ **Minting (current state, 2.0.0-alpha):** the `dev` and `prod` keys are **shared secrets
101
+ configured on the SmartLinks backend** one `dev` key and one `prod` key covering all
102
+ first-party apps. There is **no self-service minting UI yet**: ask the platform owner for the
103
+ `dev` key and put it in your workspace Build Secret. Per-app keys, self-service minting, and
104
+ rotation are planned; rotating the shared `dev` key just means updating the one Build Secret
105
+ (registered releases are unaffected — the key authorizes *writes*, it isn't stored on releases).
106
+
107
+ Present the key in the `x-smartlinks-deploy-key` header.
88
108
 
89
109
  ---
90
110
 
91
111
  ## The registration endpoint
92
112
 
93
113
  ```
94
- POST https://<smartlinks-api>/api/v1/apps/{appId}/releases
114
+ POST https://smartlinks.app/api/v1/apps/{appId}/releases # main SaaS; a VPC env uses its own host
95
115
  x-smartlinks-deploy-key: <your deploy key>
96
116
  Content-Type: application/json
97
117
  ```
@@ -124,6 +144,15 @@ Each validation error is `{ code, message, path }`, e.g.:
124
144
  ]}
125
145
  ```
126
146
 
147
+ ### Re-registering & version collisions
148
+
149
+ Registration is an **upsert keyed by (app, channel)** — the newest registration becomes that
150
+ channel's live release. Registering again **overwrites** it (last write wins); there is **no**
151
+ version-collision error even if `meta.version` is unchanged. So re-publishing to `dev` without
152
+ bumping the version is a normal, intentional overwrite — which is what you want on `dev`. (A
153
+ stricter `prod` policy that rejects a duplicate `version` may come later; it isn't enforced
154
+ today.)
155
+
127
156
  ### What gets validated
128
157
 
129
158
  - `manifest.meta.appId` must match the `{appId}` in the URL.
@@ -145,24 +174,36 @@ so a bad install fails the publish.
145
174
  import { readFileSync } from 'node:fs'
146
175
  import { execSync } from 'node:child_process'
147
176
 
148
- const API = process.env.SMARTLINKS_API || 'https://api.smartlinks.app'
149
- const KEY = process.env.SMARTLINKS_DEPLOY_KEY // dev key (in source/env) or prod key (Cloud Build)
150
- const CHANNEL = process.env.SMARTLINKS_CHANNEL || 'dev' // 'prod' in Cloud Build
177
+ const API = process.env.SMARTLINKS_API || 'https://smartlinks.app' // a VPC env: set to its host
178
+ const KEY = process.env.SMARTLINKS_DEPLOY_KEY // Lovable Build Secret (dev) / CI secret (prod)
179
+ const CHANNEL = process.env.SMARTLINKS_CHANNEL // 'dev' | 'beta' | 'prod'; UNSET don't register
180
+
181
+ // --- Gate: only register when this build is meant to ---
182
+ // A preview / live-edit build (no channel) skips quietly so it never fails. A build that
183
+ // declares a channel but has no key is a hard error IF it's prod; dev skips quietly.
184
+ if (!CHANNEL) {
185
+ console.log('ℹ︎ SmartLinks: SMARTLINKS_CHANNEL unset — skipping release registration (preview build).')
186
+ process.exit(0)
187
+ }
188
+ if (!KEY) {
189
+ if (CHANNEL === 'prod') { console.error('❌ prod build but SMARTLINKS_DEPLOY_KEY is missing'); process.exit(1) }
190
+ console.log(`ℹ︎ SmartLinks: no deploy key for "${CHANNEL}" — skipping registration.`)
191
+ process.exit(0)
192
+ }
151
193
 
152
194
  const manifest = JSON.parse(readFileSync('dist/app.manifest.json', 'utf8'))
153
195
  const appId = manifest.meta.appId
154
196
  const version = manifest.meta.version
155
197
  const gitHash = (() => { try { return execSync('git rev-parse --short HEAD').toString().trim() } catch { return null } })()
198
+ // dev: your published Lovable URL; prod: the SmartLinks CDN base. Set SMARTLINKS_BUNDLE_BASE_URL.
199
+ const bundleBaseUrl = process.env.SMARTLINKS_BUNDLE_BASE_URL || `https://smartlinks.app/apps/${appId}/${version}`
156
200
 
157
201
  const res = await fetch(`${API}/api/v1/apps/${appId}/releases`, {
158
202
  method: 'POST',
159
203
  headers: { 'content-type': 'application/json', 'x-smartlinks-deploy-key': KEY },
160
204
  body: JSON.stringify({
161
- channel: CHANNEL,
162
- version,
163
- build: { at: new Date().toISOString(), gitHash, builder: CHANNEL === 'dev' ? 'lovable' : 'cloudbuild' },
164
- manifest,
165
- bundleBaseUrl: `https://smartlinks.app/apps/${appId}/${version}`,
205
+ channel: CHANNEL, version, manifest, bundleBaseUrl,
206
+ build: { at: new Date().toISOString(), gitHash, builder: CHANNEL === 'dev' ? 'lovable' : 'ci' },
166
207
  }),
167
208
  })
168
209
 
@@ -175,7 +216,7 @@ if (!res.ok || !body.ok) {
175
216
  console.log(`✅ Registered ${appId}@${version} on "${CHANNEL}" — functions: ${(body.functions || []).join(', ') || 'none'}`)
176
217
  ```
177
218
 
178
- Wire it after your bundle build/hash step, e.g.:
219
+ Wire it after your bundle build/hash step:
179
220
 
180
221
  ```jsonc
181
222
  // package.json
@@ -185,9 +226,19 @@ Wire it after your bundle build/hash step, e.g.:
185
226
  }
186
227
  ```
187
228
 
188
- - **Dev (Lovable "Publish")** runs `build` `postbuild` with the **dev key** and
189
- `SMARTLINKS_CHANNEL=dev`.
190
- - **Prod (Cloud Build)** runs the same with the **prod key** and `SMARTLINKS_CHANNEL=prod`.
229
+ Registration is gated by **`SMARTLINKS_CHANNEL`**, so the three Lovable build types behave correctly:
191
230
 
192
- That's it: hitting Publish now validates and registers your app — and a broken manifest or
193
- function stops the deploy with an actionable error instead of shipping.
231
+ | Build | `SMARTLINKS_CHANNEL` | Result |
232
+ |---|---|---|
233
+ | **Preview / live-edit** | unset | **skips quietly** — never registers, never fails |
234
+ | **Dev (Publish)** | `dev` | registers to `dev` with the workspace Build-Secret key + your Lovable `SMARTLINKS_BUNDLE_BASE_URL` |
235
+ | **Prod (CI)** | `prod` | registers to `prod` with the prod key; a missing key **hard-fails** |
236
+
237
+ The gate is `SMARTLINKS_CHANNEL`, so **set it only where you want a release** — i.e. on the
238
+ Publish/CI build, not on preview. If your host exposes a publish-only signal (an env var it sets
239
+ only on Publish), key `SMARTLINKS_CHANNEL` off that; otherwise set it in the Publish build's env
240
+ and leave it unset for preview. That one variable is the difference between "this build ships a
241
+ release" and "this build is just a preview."
242
+
243
+ That's it: a real Publish validates + registers your app (a broken manifest or function stops
244
+ the deploy with an actionable error), while preview builds stay quiet.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@proveanything/smartlinks",
3
- "version": "2.0.0-alpha.1",
3
+ "version": "2.0.0-alpha.2",
4
4
  "description": "Official JavaScript/TypeScript SDK for the Smartlinks API",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",