@mortar-ai/skill 0.7.0 → 0.7.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.
package/README.md CHANGED
@@ -1,7 +1,8 @@
1
- # @mortar-ai/skill
1
+ # Appunvs Cloud (Mortar) Skill
2
2
 
3
- [Agent Skills](https://agentskills.io/) package for building on **Mortar** (the
4
- BaaS that AI bundles talk to). Install the canonical `SKILL.md` and its
3
+ [Agent Skills](https://agentskills.io/) package for building on **Appunvs
4
+ Cloud**, powered by the Mortar BaaS. The package and Skill ID retain the stable
5
+ `mortar` engineering name. Install the canonical `SKILL.md` and its
5
6
  `references/` into a compatible agent's skill directory to teach it the SDK
6
7
  core invariants plus on-demand capability references. The split keeps Fabric's
7
8
  loaded prompt small without hiding the storage, realtime, functions, auth, or
package/SKILL.md CHANGED
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: mortar
3
- description: Build or change Fabric applications that use Mortar capabilities such as database, auth, storage, realtime, functions, analytics, automation, or messaging. Use for Mortar schema and provisioning, SDK integration, access policy, transactions, or backend consistency; not for Fabric's own control plane or a different backend.
3
+ description: Build or change Fabric applications that use Appunvs Cloud capabilities powered by Mortar, such as database, auth, storage, realtime, functions, analytics, automation, or messaging. Use for Mortar schema and provisioning, SDK integration, access policy, transactions, or backend consistency; not for Fabric's own control plane or a different backend.
4
4
  metadata:
5
5
  activation: auto
6
6
  priority: high
@@ -8,10 +8,12 @@ metadata:
8
8
  - keywords: [database, 数据库, backend, 后端, auth, authentication, 登录, 认证, persistence, 持久化, transaction, 事务, ACID, storage, upload, 文件, realtime, 实时, collaboration, function, compute, analytics, cron, queue, comms, secrets, billing, cloud, 云端]
9
9
  ---
10
10
 
11
- # Mortar for Fabric applications
11
+ # Appunvs Cloud (Mortar) for Fabric applications
12
12
 
13
- Mortar is an independent Backend-as-a-Service used by Fabric-built apps; Fabric
14
- itself does not run on Mortar. Do not infer its setup from another BaaS.
13
+ Appunvs Cloud is the user-facing product powered by the independent Mortar
14
+ Backend-as-a-Service. Fabric-built apps may use it; Fabric itself does not run
15
+ on Mortar. `mortar` remains the stable SDK, tool, API, and source identity. Do
16
+ not infer its setup from another BaaS.
15
17
 
16
18
  ## Fabric integration contract
17
19
 
@@ -81,7 +83,10 @@ below; if platform provisioning fails, report that platform failure.
81
83
  one-table batch or filtered mutation may use the public singleton;
82
84
  cross-table row + queue transactions require trusted server code; object
83
85
  storage and external services never join a PostgreSQL transaction.
84
- 8. Type-check and build. Handle every `{ data, error }` SDK result in UI code.
86
+ 8. Read `references/errors.md` and handle both `{ data, error }` results and
87
+ thrown SDK failures according to the surrounding application's domain and
88
+ interaction design. Follow the application's existing architecture; Mortar
89
+ must not prescribe or introduce a shared UI adapter. Type-check and build.
85
90
 
86
91
  Supported database DDL is `CREATE TABLE`, `DROP TABLE`, `ALTER TABLE … ADD/DROP
87
92
  COLUMN`, `ALTER TABLE … SET ACCESS`, and `CREATE INDEX`. Put
@@ -106,7 +111,12 @@ type names guide application types but do not runtime-validate payload values.
106
111
  recreate a table merely to change permissions.
107
112
  - For a public form, registration, or evidence upload reviewed by an operator,
108
113
  use table/bucket access `public_insert`. It permits new submissions while
109
- denying anonymous list, read, update, delete, and overwrite.
114
+ denying anonymous list, read, update, delete, and overwrite. That anonymous
115
+ restriction is not a blanket browser restriction: an authenticated AppUser
116
+ with `data_role=admin`, or trusted `app`/`admin` scope, may read and moderate
117
+ rows according to the server policy. Before deploying a Function for an
118
+ operator mutation, verify the active session and access policy; use the
119
+ authenticated SDK mutation directly when the data-admin path is supported.
110
120
  - Never use `public` merely to make anonymous submission work: it exposes all
111
121
  rows or files for public read and mutation.
112
122
  - Generate an unguessable logical object key for each public upload.
@@ -146,6 +156,8 @@ Agent Skills hosts resolve the same paths relative to this `SKILL.md`.
146
156
  `references/realtime.md`
147
157
  - Function deployment/invocation, logs, public-key boundaries, and error
148
158
  handling: `references/functions.md`
159
+ - Normalized SDK errors, `{ data, error }` versus thrown calls, retry facts,
160
+ correlation IDs, and Function error ownership: `references/errors.md`
149
161
  - The 9 infrastructure primitives, open capability registry, application
150
162
  modules, usage accounting, and trust surfaces: `references/architecture.md`
151
163
  - Product analytics, error capture, delivery guarantees, and operator summary:
@@ -168,6 +180,11 @@ for example:
168
180
  sed -n '1,240p' /tmp/skills/mortar/references/storage.md
169
181
  ```
170
182
 
183
+ Materialized `/tmp/skills/...` references are outside the project tree: read
184
+ them through `bash`, not `read_file` or `grep_search`. The Runner does not
185
+ guarantee `rg`; use `grep` to locate an `operationId` and `sed` for the bounded
186
+ section.
187
+
171
188
  ## Completion checklist
172
189
 
173
190
  - Live schema was read before schema design.
@@ -185,7 +202,8 @@ sed -n '1,240p' /tmp/skills/mortar/references/storage.md
185
202
  durable backend guarantee.
186
203
  - No secret/admin client or hand-written fallback configuration entered the
187
204
  client bundle.
188
- - Every SDK error path is handled.
205
+ - Every SDK error path has an application-owned failure boundary; Mortar error
206
+ metadata does not dictate the application's UI or recovery flow.
189
207
  - The relevant on-demand reference—not every reference—was consulted.
190
208
  - Type-check and the surface's real build pass.
191
209
 
package/manifest.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schema_version": 1,
3
3
  "id": "mortar",
4
- "version": "0.7.0",
5
- "content_sha256": "sha256:ec235e0f2e9c38e64ab906c8daca2daa98482313a4004fd1a73bc30f17671487",
4
+ "version": "0.7.2",
5
+ "content_sha256": "sha256:b0240a03057ebc2cf8b831e198e5769644d5ea8a7645b7e5a7a6d22965db2ef1",
6
6
  "source_repo": "liamxujia/appunvs",
7
7
  "source_path": "mortar/skill",
8
8
  "distributions": [
@@ -11,6 +11,6 @@
11
11
  ],
12
12
  "npm": {
13
13
  "package": "@mortar-ai/skill",
14
- "version": "0.7.0"
14
+ "version": "0.7.2"
15
15
  }
16
16
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@mortar-ai/skill",
3
- "version": "0.7.0",
4
- "description": "Agent skill package for building Fabric applications on Mortar (BaaS), with compact core guidance and on-demand references.",
3
+ "version": "0.7.2",
4
+ "description": "Agent skill for building Fabric applications on Appunvs Cloud powered by Mortar, with compact core guidance and on-demand references.",
5
5
  "main": "index.js",
6
6
  "files": ["SKILL.md", "references", "manifest.json", "index.js", "README.md"],
7
7
  "bin": {
@@ -60,6 +60,38 @@ not claim direct public insert satisfies it. Use a reviewed supported
60
60
  server-side contract that really performs atomic deduplication, or state that
61
61
  the guarantee is not currently available for that client path.
62
62
 
63
+ ## `public_insert` and data-admin moderation
64
+
65
+ `public_insert` means anonymous write-only intake, not that every browser
66
+ session is forbidden from reading or changing rows. An authenticated AppUser
67
+ whose current token has `data_role=admin` can read and moderate those rows;
68
+ trusted `app` and `admin` scopes can do the same. The injected SDK resolves the
69
+ managed AppUser session and attaches its access token automatically, so do not
70
+ ask application code to copy tokens or put privileged project keys in a bundle.
71
+
72
+ For an operator edit supported by that policy, use the authenticated singleton
73
+ directly and handle the result:
74
+
75
+ ```ts
76
+ const { data, error, count } = await mortar
77
+ .from('submissions')
78
+ .update({ display_name: cleanName })
79
+ .eq('id', submissionId)
80
+ .select();
81
+ if (error) throw new Error(error.message);
82
+ ```
83
+
84
+ If the target table has a database trigger that performs the required
85
+ cross-table cascade, the triggering row update and that cascade run inside the
86
+ database transaction. Moving the same update behind a Function does not make
87
+ the database work more atomic; it only adds a compute/network boundary.
88
+
89
+ Do not deploy a Function merely to bypass a policy that was not verified.
90
+ Use trusted server code only when the current authenticated data-admin path is
91
+ actually unsupported, or when the operation needs a server secret, an external
92
+ provider, or a supported cross-table transaction that no database trigger
93
+ already provides.
94
+
63
95
  ## Atomic row mutations
64
96
 
65
97
  Pass an array when every insert or upsert must succeed or fail together. Mortar
@@ -0,0 +1,111 @@
1
+ # Error handling reference
2
+
3
+ Read this reference whenever application code calls Mortar. Mortar provides
4
+ structured failure facts; the application owns their product meaning and user
5
+ experience.
6
+
7
+ ## One normalized error, two JavaScript call shapes
8
+
9
+ Mortar's TypeScript SDK exposes one canonical `MortarApiError` model:
10
+
11
+ - `code`: stable machine code from the server's `error` field
12
+ - `category`: technical class such as `validation`, `authentication`, `quota`,
13
+ `rate_limit`, `dependency`, `network`, or `timeout`
14
+ - `status`: HTTP status, or `0` for a client/transport failure
15
+ - `requestId`: correlation ID from `X-Request-ID`
16
+ - `retryable` and `retryAfterMs`: transport and retry hints
17
+ - `body`: the original structured server error
18
+
19
+ Supabase-compatible query/auth/storage helpers return failures as
20
+ `{ data, error }`. Other SDK methods throw `MortarApiError`. Both shapes carry
21
+ the same underlying Mortar fields; the envelope changes control flow, not the
22
+ meaning of the error.
23
+
24
+ Always check an envelope's `error` before using `data`:
25
+
26
+ ```ts
27
+ const { data, error } = await mortar.from('todos').insert(input);
28
+ if (error) {
29
+ handleTodoCreateFailure(error); // Defined by this application and feature.
30
+ return;
31
+ }
32
+ useCreatedTodo(data);
33
+ ```
34
+
35
+ Throwing APIs already expose `MortarApiError`. When a catch binding is
36
+ `unknown`, `normalizeMortarError` converts transport and SDK failures into the
37
+ same technical model without choosing application behavior:
38
+
39
+ ```ts
40
+ import { normalizeMortarError } from '@mortar-ai/client';
41
+
42
+ try {
43
+ await mortar.storage.upload({ bucket: 'receipts', key, body: file });
44
+ } catch (cause) {
45
+ const error = normalizeMortarError(cause, 'upload receipt');
46
+ handleReceiptUploadFailure(error); // Application-defined, not SDK-defined.
47
+ }
48
+ ```
49
+
50
+ ## Error facts are not interaction policy
51
+
52
+ Mortar does not prescribe a toast, modal, inline field error, navigation,
53
+ reauthentication flow, localization key, reporting rule, or centralized UI
54
+ adapter. An application may handle failures per feature or reuse its own
55
+ abstraction when that matches its architecture.
56
+
57
+ In particular:
58
+
59
+ - `category` is a technical grouping, not a UI action. For example,
60
+ `authentication` does not require immediate navigation to a sign-in screen.
61
+ - `retryable` is a hint that the failure may succeed later, not permission to
62
+ replay the operation automatically.
63
+ - `retryAfterMs` is server timing information, not a required countdown UI.
64
+ - `requestId` supports correlation, but the application decides whether and
65
+ where it is recorded or presented.
66
+ - `body`, `detail`, and `message` are diagnostic data. They are not guaranteed
67
+ to be localized, stable, sanitized for end users, or safe as control-flow
68
+ keys. Branch on stable codes and structured fields instead.
69
+
70
+ Mutating operations are never automatically replayed without an idempotency guarantee.
71
+ An insert, payment, message send, upload, or Function mutation may already have
72
+ completed when the client observes a network failure. Require a documented
73
+ idempotency contract or an explicit application decision before replaying it.
74
+
75
+ ## Function responses are a separate contract
76
+
77
+ `mortar.compute.invoke(...)` throws only for Mortar platform failures marked by
78
+ `X-Mortar-Error: platform`. A tenant Function's response stays a raw
79
+ `Response`, including 4xx and 5xx statuses, because its business-error schema
80
+ belongs to that Function:
81
+
82
+ ```ts
83
+ try {
84
+ const response = await mortar.compute.invoke({
85
+ name: 'create-checkout',
86
+ body: JSON.stringify(input),
87
+ contentType: 'application/json',
88
+ });
89
+
90
+ if (!response.ok) {
91
+ const problem = await response.json();
92
+ applyCheckoutProblem(problem); // Function-owned application contract
93
+ return;
94
+ }
95
+ } catch (error) {
96
+ handleCheckoutPlatformFailure(error); // Application-defined for this operation.
97
+ }
98
+ ```
99
+
100
+ Do not interpret a tenant Function's business body as a Mortar platform error,
101
+ and do not infer error ownership from HTTP status alone.
102
+
103
+ ## Completion checks
104
+
105
+ - Every `{ data, error }` result checks `error` before using `data`.
106
+ - Every throwing Mortar operation has a deliberate application failure boundary.
107
+ - Control flow uses stable error codes and fields rather than diagnostic text.
108
+ - The application, not Mortar, determines UI, localization, navigation,
109
+ reporting, and recovery behavior.
110
+ - Mutating operations are never automatically replayed without an idempotency guarantee.
111
+ - Function business errors follow the Function's documented response schema.
@@ -19,25 +19,51 @@ removes the manifest, both entrypoint forms, and the legacy flat `.js` artifact.
19
19
  Client bundles may invoke a function that the platform already deployed:
20
20
 
21
21
  ```ts
22
- const response = await mortar.compute.invoke({
23
- name: 'create-checkout',
24
- method: 'POST',
25
- body: JSON.stringify({ orderId }),
26
- contentType: 'application/json',
27
- });
28
-
29
- if (!response.ok) {
30
- throw new Error(`Function failed: ${response.status} ${await response.text()}`);
22
+ try {
23
+ const response = await mortar.compute.invoke({
24
+ name: 'create-checkout',
25
+ method: 'POST',
26
+ body: JSON.stringify({ orderId }),
27
+ contentType: 'application/json',
28
+ });
29
+
30
+ if (!response.ok) {
31
+ const problem = await response.json();
32
+ applyCheckoutProblem(problem); // Function-owned business contract
33
+ return;
34
+ }
35
+ const result = await response.json();
36
+ useCheckout(result);
37
+ } catch (error) {
38
+ handleCheckoutPlatformFailure(error); // Application-defined for this operation.
31
39
  }
32
- const result = await response.json();
33
40
  ```
34
41
 
35
42
  `compute.invoke` is the only public-key compute operation. Mortar infrastructure
36
- errors such as unavailable compute or timeout throw; user-function status codes
37
- are returned as the raw `Response`, so check `response.ok` and consume the body.
43
+ errors marked by `X-Mortar-Error: platform` throw; user-function status codes
44
+ are returned as the raw `Response`, so check `response.ok` and consume the body
45
+ according to that Function's documented business-error schema. HTTP status alone
46
+ does not identify which side produced the error. See `errors.md` for the shared
47
+ platform-error facts and the application-owned policy boundary.
38
48
  Function deployment/logs remain operator-side capabilities and must never be
39
49
  recreated with an app/admin key in a browser or mobile bundle.
40
50
 
51
+ ## When not to deploy a Function
52
+
53
+ Check the authenticated row-policy path before introducing compute. In
54
+ particular, `public_insert` denies anonymous reads and mutations but permits an
55
+ authenticated AppUser with `data_role=admin` to moderate rows. When that path
56
+ matches the product requirement, call the row SDK with the managed user session
57
+ instead of deploying a Function merely to obtain an `app` scope.
58
+
59
+ A database trigger invoked by one row mutation already runs in the database
60
+ transaction with that mutation. Wrapping the update in a Function does not make
61
+ the trigger cascade more atomic and adds a separate network/compute failure
62
+ boundary. If a Function is genuinely required, authorize it with a verified
63
+ user JWT or another server-trusted identity. Never accept caller-supplied names,
64
+ employee numbers, roles, or similar request fields as proof of administrator
65
+ identity.
66
+
41
67
  Functions and external providers do not join the caller's PostgreSQL
42
68
  transaction. Make externally visible operations idempotent and persist explicit
43
69
  pending/succeeded/failed state when a workflow must recover.
@@ -1,7 +1,7 @@
1
1
  openapi: 3.0.3
2
2
  info:
3
3
  title: Mortar REST API
4
- version: "0.2.1"
4
+ version: "0.3.0"
5
5
  description: |
6
6
  Backend-as-a-Service for mainland-China-friendly mobile and web apps.
7
7
 
@@ -21,12 +21,12 @@ info:
21
21
  * `AccountToken` — Account session JWT minted by
22
22
  `/v1/_accounts/signin`, or an Account PAT (`mtr_pat_*`); scopes all
23
23
  `/v1/_accounts/*` and project-lifecycle calls to one Mortar account.
24
- * `APIKey` — Bearer token starting with `mtr_live_` (production) or
25
- `mtr_test_` (sandbox); scopes a single project (its tenant_id) and one of
26
- `admin` / `app` / `public` privilege tiers.
24
+ * `APIKey` — raw `X-Mortar-API-Key` value starting with `mtr_live_`
25
+ (production) or `mtr_test_` (sandbox); scopes a single project (its
26
+ tenant_id) and one of `admin` / `app` / `public` privilege tiers.
27
27
 
28
28
  Signed-in project users may additionally send a User access JWT in
29
- `X-Mortar-User-Token`. That optional identity layer is not modeled
29
+ `Authorization: Bearer <jwt>`. That optional identity layer is not modeled
30
30
  consistently by every operation in this partial document.
31
31
 
32
32
  Errors use a uniform `{ "error": "<machine_code>" }` body, occasionally
@@ -1856,12 +1856,19 @@ components:
1856
1856
  use and may be passed via the `MORTAR_ACCOUNT_TOKEN` env var to
1857
1857
  the `mortar` CLI.
1858
1858
  APIKey:
1859
+ type: apiKey
1860
+ in: header
1861
+ name: X-Mortar-API-Key
1862
+ description: |
1863
+ Project-scope API key starting with `mtr_live_` (production) or
1864
+ `mtr_test_` (sandbox), sent as the raw `X-Mortar-API-Key` value.
1865
+ UserToken:
1859
1866
  type: http
1860
1867
  scheme: bearer
1861
- bearerFormat: opaque
1868
+ bearerFormat: JWT
1862
1869
  description: |
1863
- Project-scope API key starting with `mtr_live_` (production) or
1864
- `mtr_test_` (sandbox). Bearer-encoded in `Authorization`.
1870
+ Optional project end-user access JWT in `Authorization: Bearer …`.
1871
+ It supplements, and never replaces, the required `X-Mortar-API-Key`.
1865
1872
 
1866
1873
  parameters:
1867
1874
  TenantPath:
@@ -1895,21 +1902,57 @@ components:
1895
1902
  responses:
1896
1903
  BadRequest:
1897
1904
  description: Malformed request.
1905
+ headers:
1906
+ X-Request-ID:
1907
+ $ref: "#/components/headers/RequestID"
1908
+ X-Mortar-Error:
1909
+ $ref: "#/components/headers/MortarErrorSource"
1898
1910
  content:
1899
1911
  application/json:
1900
1912
  schema:
1901
1913
  $ref: "#/components/schemas/Error"
1902
1914
 
1915
+ headers:
1916
+ RequestID:
1917
+ description: Stable correlation ID echoed by Mortar for this request.
1918
+ schema:
1919
+ type: string
1920
+ MortarErrorSource:
1921
+ description: Present as `platform` when the response was generated by Mortar rather than a tenant Function.
1922
+ schema:
1923
+ type: string
1924
+ enum: [platform]
1925
+
1903
1926
  schemas:
1904
1927
  Error:
1905
1928
  type: object
1906
- required: [error]
1929
+ required: [error, category, request_id]
1907
1930
  properties:
1908
1931
  error:
1909
1932
  type: string
1910
1933
  description: Machine-readable error code (e.g. `invalid_body`).
1911
1934
  detail:
1912
1935
  type: string
1936
+ description: Optional diagnostic detail; applications should localize from `error` instead of displaying this directly.
1937
+ category:
1938
+ type: string
1939
+ description: Stable application-level recovery category.
1940
+ enum: [validation, authentication, permission, not_found, conflict, quota, rate_limit, dependency, internal]
1941
+ request_id:
1942
+ type: string
1943
+ description: Correlation ID matching the `X-Request-ID` response header.
1944
+ retryable:
1945
+ type: boolean
1946
+ description: Whether retrying may succeed. Mutating requests still require an idempotency-safe operation.
1947
+ retry_after_sec:
1948
+ type: integer
1949
+ minimum: 0
1950
+ description: Server-requested delay before retrying, also represented by `Retry-After` when present.
1951
+ fields:
1952
+ type: array
1953
+ description: Optional application input fields associated with a validation error.
1954
+ items:
1955
+ type: string
1913
1956
 
1914
1957
  Account:
1915
1958
  type: object
@@ -17,7 +17,7 @@ never edit them to request a schema change.
17
17
  Search the OpenAPI by stable operation ID, for example:
18
18
 
19
19
  ```sh
20
- rg -n 'operationId: (insertDatabaseRows|listDatabaseRows)' \
20
+ grep -nE 'operationId: (insertDatabaseRows|listDatabaseRows)' \
21
21
  /tmp/skills/mortar/references/openapi.yaml
22
22
  ```
23
23