@jskit-ai/agent-docs 0.1.257 → 0.1.259
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/guide/agent/app-extras/assistant-conversation.md +88 -35
- package/guide/agent/app-extras/assistant.md +28 -28
- package/guide/agent/app-setup/authentication.md +36 -17
- package/guide/agent/app-setup/database-layer.md +116 -17
- package/guide/agent/app-setup/existing-application-migration.md +29 -25
- package/guide/agent/app-setup/multi-homing.md +94 -48
- package/guide/agent/app-setup/run-an-accounts-hub.md +6 -4
- package/guide/agent/framework/client-features.md +496 -0
- package/guide/agent/framework/crud-operations.md +5 -5
- package/guide/agent/framework/translation.md +4 -3
- package/guide/agent/framework/typed-features.md +1104 -0
- package/guide/agent/framework/ui-operations.md +2 -2
- package/guide/agent/index.md +6 -1
- package/package.json +1 -1
- package/patterns/feature-package/PATTERN.md +104 -10
- package/patterns/feature-package/example/booking-engine/package.json +9 -4
- package/patterns/feature-package/example/booking-engine/src/server/BookingEngineFeature.js +24 -0
- package/patterns/feature-package/example/booking-engine/src/server/bookingAvailability.js +10 -0
- package/patterns/feature-package/example/booking-engine/src/server/bookingEngine.js +29 -0
- package/patterns/feature-package/example/booking-engine/src/server/bookingEngineActions.js +26 -0
- package/patterns/feature-package/example/booking-engine/src/server/inputSchemas.js +1 -2
- package/patterns/feature-package/example/booking-engine/src/server/types.js +12 -0
- package/patterns/feature-package/example/variations/AvailabilityEngineFeature.js +19 -0
- package/patterns/feature-package/example/variations/InvoiceRollupFeature.js +23 -0
- package/patterns/feature-package/example/variations/availabilityEngineActions.js +26 -0
- package/patterns/feature-package/example/variations/customKnexRepository.js +32 -26
- package/patterns/feature-package/example/variations/invoiceRollupActions.js +26 -0
- package/patterns/feature-package/example/variations/orchestratorService.js +24 -19
- package/patterns/feature-package/example/variations/types.js +7 -0
- package/patterns/minimal-foundation/PATTERN.md +30 -1
- package/patterns/minimal-foundation/example/AGENTS.md +14 -0
- package/patterns/minimal-foundation/example/bin/develop.js +10 -5
- package/patterns/minimal-foundation/example/eslint.config.mjs +21 -2
- package/patterns/minimal-foundation/example/package.json +5 -4
- package/patterns/minimal-foundation/example/playwright.config.mjs +1 -1
- package/patterns/minimal-foundation/example/server/lib/envFile.js +19 -0
- package/patterns/minimal-foundation/example/server/lib/loggerOptions.js +15 -0
- package/patterns/minimal-foundation/example/server/lib/runtimeEnv.js +17 -17
- package/patterns/minimal-foundation/example/server.js +32 -29
- package/patterns/minimal-foundation/example/tests/server/smoke.test.js +2 -1
- package/patterns/shell-foundation/PATTERN.md +29 -0
- package/patterns/shell-foundation/example/AGENTS.md +14 -0
- package/patterns/shell-foundation/example/bin/develop.js +10 -5
- package/patterns/shell-foundation/example/eslint.config.mjs +21 -2
- package/patterns/shell-foundation/example/package.json +6 -5
- package/patterns/shell-foundation/example/packages/main/package.json +1 -1
- package/patterns/shell-foundation/example/packages/main/src/client/providers/MainClientProvider.js +1 -0
- package/patterns/shell-foundation/example/playwright.config.mjs +1 -1
- package/patterns/shell-foundation/example/server/lib/envFile.js +19 -0
- package/patterns/shell-foundation/example/server/lib/loggerOptions.js +15 -0
- package/patterns/shell-foundation/example/server/lib/runtimeEnv.js +17 -17
- package/patterns/shell-foundation/example/server.js +32 -29
- package/patterns/shell-foundation/example/tests/server/smoke.test.js +2 -1
- package/reference/autogen/KERNEL_MAP.md +14 -8
- package/reference/autogen/PATTERN_INDEX.md +37 -37
- package/reference/autogen/README.md +2 -0
- package/reference/autogen/packages/agent-docs.md +70 -26
- package/reference/autogen/packages/agent-runtime.md +129 -0
- package/reference/autogen/packages/agent.md +149 -0
- package/reference/autogen/packages/architecture-inspector.md +97 -44
- package/reference/autogen/packages/assistant-core.md +786 -292
- package/reference/autogen/packages/assistant-runtime.md +182 -57
- package/reference/autogen/packages/assistant-voice-sherpa.md +4 -0
- package/reference/autogen/packages/assistant-voice.md +54 -8
- package/reference/autogen/packages/auth-core.md +44 -13
- package/reference/autogen/packages/auth-provider-local-core.md +86 -34
- package/reference/autogen/packages/auth-provider-local-db-core.md +1 -2
- package/reference/autogen/packages/auth-provider-oidc-core.md +10 -4
- package/reference/autogen/packages/auth-provider-supabase-core.md +52 -66
- package/reference/autogen/packages/auth-web.md +19 -11
- package/reference/autogen/packages/connectors-catalog.md +71 -43
- package/reference/autogen/packages/connectors-core.md +42 -4
- package/reference/autogen/packages/console-core.md +27 -14
- package/reference/autogen/packages/crud-core.md +178 -170
- package/reference/autogen/packages/database-runtime-mysql.md +0 -2
- package/reference/autogen/packages/database-runtime-postgres.md +0 -2
- package/reference/autogen/packages/database-runtime.md +39 -10
- package/reference/autogen/packages/http-runtime.md +79 -57
- package/reference/autogen/packages/json-rest-api-core.md +11 -8
- package/reference/autogen/packages/kernel.md +144 -83
- package/reference/autogen/packages/oidc-issuer-core.md +49 -20
- package/reference/autogen/packages/payments-core.md +20 -3
- package/reference/autogen/packages/realtime.md +47 -22
- package/reference/autogen/packages/resource-core.md +1 -1
- package/reference/autogen/packages/resource-crud-core.md +64 -26
- package/reference/autogen/packages/rewarded-core.md +47 -36
- package/reference/autogen/packages/shell-web.md +7 -10
- package/reference/autogen/packages/storage-runtime.md +6 -2
- package/reference/autogen/packages/uploads-runtime.md +10 -2
- package/reference/autogen/packages/users-core.md +73 -71
- package/reference/autogen/packages/workspaces-core.md +121 -106
- package/reference/autogen/packages/workspaces-web.md +1 -2
- package/reference/autogen/tooling/config-eslint.md +302 -0
- package/reference/autogen/tooling/jskit-catalog.md +28 -18
- package/reference/autogen/tooling/jskit-release.md +35 -20
- package/reference/autogen/tooling/testUtils.md +3 -1
- package/skills/jskit/SKILL.md +9 -8
- package/skills/jskit/references/app-operations.md +1 -1
- package/skills/jskit/references/client-features.md +491 -0
- package/skills/jskit/references/crud-form-actions.md +1 -1
- package/skills/jskit/references/crud-operations.md +7 -7
- package/skills/jskit/references/existing-application-migration.md +31 -27
- package/skills/jskit/references/heuristics/INDEX.md +5 -1
- package/skills/jskit/references/heuristics/child-cruds.md +1 -1
- package/skills/jskit/references/heuristics/client-features.md +66 -0
- package/skills/jskit/references/heuristics/client-requests.md +1 -1
- package/skills/jskit/references/heuristics/crud-authoring.md +12 -2
- package/skills/jskit/references/heuristics/crud-links.md +1 -1
- package/skills/jskit/references/heuristics/crud-repository-mapping.md +3 -3
- package/skills/jskit/references/heuristics/filters.md +1 -1
- package/skills/jskit/references/heuristics/live-actions.md +1 -1
- package/skills/jskit/references/heuristics/page-redirects.md +1 -1
- package/skills/jskit/references/heuristics/page-scaffolding.md +1 -1
- package/skills/jskit/references/heuristics/placements.md +1 -1
- package/skills/jskit/references/heuristics/row-policies.md +1 -1
- package/skills/jskit/references/heuristics/server-search.md +1 -1
- package/skills/jskit/references/heuristics/surfaces.md +1 -1
- package/skills/jskit/references/heuristics/typed-features.md +100 -0
- package/skills/jskit/references/heuristics/ui-contract.md +1 -1
- package/skills/jskit/references/heuristics/ui-testing.md +4 -4
- package/skills/jskit/references/material-3.md +2 -2
- package/skills/jskit/references/multi-homing.md +96 -50
- package/skills/jskit/references/pattern-index.md +37 -37
- package/skills/jskit/references/patterns/app/minimal-foundation/PATTERN.md +30 -1
- package/skills/jskit/references/patterns/app/minimal-foundation/example/AGENTS.md +14 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/bin/develop.js +10 -5
- package/skills/jskit/references/patterns/app/minimal-foundation/example/eslint.config.mjs +21 -2
- package/skills/jskit/references/patterns/app/minimal-foundation/example/package.json +5 -4
- package/skills/jskit/references/patterns/app/minimal-foundation/example/playwright.config.mjs +1 -1
- package/skills/jskit/references/patterns/app/minimal-foundation/example/server/lib/envFile.js +19 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/server/lib/loggerOptions.js +15 -0
- package/skills/jskit/references/patterns/app/minimal-foundation/example/server/lib/runtimeEnv.js +17 -17
- package/skills/jskit/references/patterns/app/minimal-foundation/example/server.js +32 -29
- package/skills/jskit/references/patterns/app/minimal-foundation/example/tests/server/smoke.test.js +2 -1
- package/skills/jskit/references/patterns/app/shell-foundation/PATTERN.md +29 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/AGENTS.md +14 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/bin/develop.js +10 -5
- package/skills/jskit/references/patterns/app/shell-foundation/example/eslint.config.mjs +21 -2
- package/skills/jskit/references/patterns/app/shell-foundation/example/package.json +6 -5
- package/skills/jskit/references/patterns/app/shell-foundation/example/packages/main/package.json +1 -1
- package/skills/jskit/references/patterns/app/shell-foundation/example/packages/main/src/client/providers/MainClientProvider.js +1 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/playwright.config.mjs +1 -1
- package/skills/jskit/references/patterns/app/shell-foundation/example/server/lib/envFile.js +19 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/server/lib/loggerOptions.js +15 -0
- package/skills/jskit/references/patterns/app/shell-foundation/example/server/lib/runtimeEnv.js +17 -17
- package/skills/jskit/references/patterns/app/shell-foundation/example/server.js +32 -29
- package/skills/jskit/references/patterns/app/shell-foundation/example/tests/server/smoke.test.js +2 -1
- package/skills/jskit/references/patterns/assistant/assistant-surface/example/src/ApplicationAiFeature.js +4 -2
- package/skills/jskit/references/patterns/auth/accounts-hub/PATTERN.md +2 -1
- package/skills/jskit/references/patterns/auth/accounts-hub/example/package.json +2 -2
- package/skills/jskit/references/patterns/auth/accounts-hub/example/server/hubPaths.js +9 -3
- package/skills/jskit/references/patterns/auth/auth-surface/PATTERN.md +25 -12
- package/skills/jskit/references/patterns/auth/auth-surface/example/tools/preview-identity +7 -1
- package/skills/jskit/references/patterns/auth/oidc-sign-in/example/package.json +2 -2
- package/skills/jskit/references/patterns/auth/supabase-auth/example/package.json +1 -1
- package/skills/jskit/references/patterns/connectors/ai-connections/PATTERN.md +16 -1
- package/skills/jskit/references/patterns/connectors/ai-connections/example/ai-model.js +12 -3
- package/skills/jskit/references/patterns/connectors/ai-connections/example/perplexity-answer.js +15 -4
- package/skills/jskit/references/patterns/connectors/api-key-connection/PATTERN.md +9 -1
- package/skills/jskit/references/patterns/connectors/api-key-connection/example/connections.js +5 -2
- package/skills/jskit/references/patterns/connectors/aws-storage-queries/PATTERN.md +13 -3
- package/skills/jskit/references/patterns/connectors/aws-storage-queries/example/s3-transfer.js +14 -3
- package/skills/jskit/references/patterns/connectors/calendar-cli/PATTERN.md +8 -0
- package/skills/jskit/references/patterns/connectors/calendar-cli/example/knexfile.js +1 -1
- package/skills/jskit/references/patterns/connectors/calendar-cli/example/package.json +4 -4
- package/skills/jskit/references/patterns/connectors/calendar-cli/example/scripts/calendar.js +8 -4
- package/skills/jskit/references/patterns/connectors/event-delivery/PATTERN.md +1 -1
- package/skills/jskit/references/patterns/connectors/firebase-messaging/PATTERN.md +10 -0
- package/skills/jskit/references/patterns/connectors/firebase-messaging/example/server/notifications.js +8 -0
- package/skills/jskit/references/patterns/connectors/google-ads-search/PATTERN.md +18 -7
- package/skills/jskit/references/patterns/connectors/google-ads-search/example/ads-setup.js +13 -5
- package/skills/jskit/references/patterns/connectors/oauth-connection/PATTERN.md +1 -1
- package/skills/jskit/references/patterns/connectors/paddle-catalogue/PATTERN.md +11 -2
- package/skills/jskit/references/patterns/connectors/paddle-catalogue/example/create-products.js +5 -2
- package/skills/jskit/references/patterns/connectors/public-image/PATTERN.md +10 -1
- package/skills/jskit/references/patterns/connectors/public-image/example/logo-url.js +4 -1
- package/skills/jskit/references/patterns/connectors/redshift-queries/PATTERN.md +1 -1
- package/skills/jskit/references/patterns/connectors/source-scanning/PATTERN.md +13 -2
- package/skills/jskit/references/patterns/connectors/source-scanning/example/source-scanner.js +9 -0
- package/skills/jskit/references/patterns/crud/json-api-resource-package/PATTERN.md +102 -23
- package/skills/jskit/references/patterns/crud/json-api-resource-package/example/packages/books/package.json +3 -2
- package/skills/jskit/references/patterns/crud/json-api-resource-package/example/packages/books/src/server/types.js +5 -0
- package/skills/jskit/references/patterns/crud/resource-contract/PATTERN.md +54 -1
- package/skills/jskit/references/patterns/database/mysql-application/PATTERN.md +16 -5
- package/skills/jskit/references/patterns/database/mysql-application/example/knexfile.js +2 -2
- package/skills/jskit/references/patterns/database/mysql-application/example/package.json +1 -1
- package/skills/jskit/references/patterns/database/mysql-application/example/scripts/prepare-database.js +1 -1
- package/skills/jskit/references/patterns/database/postgres-application/PATTERN.md +16 -5
- package/skills/jskit/references/patterns/database/postgres-application/example/knexfile.js +2 -2
- package/skills/jskit/references/patterns/database/postgres-application/example/package.json +1 -1
- package/skills/jskit/references/patterns/database/postgres-application/example/scripts/prepare-database.js +1 -1
- package/skills/jskit/references/patterns/realtime/realtime-application/example/package.json +2 -2
- package/skills/jskit/references/patterns/rewards/google-rewarded/example/GoogleRewardedDeliveryProvider.js +1 -1
- package/skills/jskit/references/patterns/rewards/google-rewarded/example/googlePublisherTag.js +5 -11
- package/skills/jskit/references/patterns/server/feature-package/PATTERN.md +104 -10
- package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/package.json +9 -4
- package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/BookingEngineFeature.js +24 -0
- package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/bookingAvailability.js +10 -0
- package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/bookingEngine.js +29 -0
- package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/bookingEngineActions.js +26 -0
- package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/inputSchemas.js +1 -2
- package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/types.js +12 -0
- package/skills/jskit/references/patterns/server/feature-package/example/variations/AvailabilityEngineFeature.js +19 -0
- package/skills/jskit/references/patterns/server/feature-package/example/variations/InvoiceRollupFeature.js +23 -0
- package/skills/jskit/references/patterns/server/feature-package/example/variations/availabilityEngineActions.js +26 -0
- package/skills/jskit/references/patterns/server/feature-package/example/variations/customKnexRepository.js +32 -26
- package/skills/jskit/references/patterns/server/feature-package/example/variations/invoiceRollupActions.js +26 -0
- package/skills/jskit/references/patterns/server/feature-package/example/variations/orchestratorService.js +24 -19
- package/skills/jskit/references/patterns/server/feature-package/example/variations/types.js +7 -0
- package/skills/jskit/references/patterns/users/user-administration-server/PATTERN.md +16 -1
- package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users/package.json +3 -2
- package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users/src/server/types.js +5 -0
- package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users-workspace/package.json +4 -3
- package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users-workspace/src/server/UsersWorkspaceFeature.js +2 -9
- package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users-workspace/src/server/types.js +5 -0
- package/skills/jskit/references/patterns/workspaces/workspace-server/PATTERN.md +42 -17
- package/skills/jskit/references/patterns/workspaces/workspace-server/example/packages/main/src/server/WorkspaceInvitationsFeature.js +27 -0
- package/skills/jskit/references/patterns/workspaces/workspace-server/example/packages/main/src/server/email/workspaceInviteEmail.js +11 -10
- package/skills/jskit/references/patterns/workspaces/workspace-server/example/packages/main/src/server/email/workspaceInviteMailer.js +27 -0
- package/skills/jskit/references/translation.md +5 -4
- package/skills/jskit/references/typed-features.md +1099 -0
- package/skills/jskit/references/ui-operations.md +3 -3
- package/patterns/feature-package/example/booking-engine/src/server/BookingEngineProvider.js +0 -33
- package/patterns/feature-package/example/booking-engine/src/server/actions.js +0 -24
- package/patterns/feature-package/example/variations/AvailabilityEngineProvider.js +0 -31
- package/patterns/feature-package/example/variations/InvoiceRollupProvider.js +0 -36
- package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/BookingEngineProvider.js +0 -33
- package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/actions.js +0 -24
- package/skills/jskit/references/patterns/server/feature-package/example/variations/AvailabilityEngineProvider.js +0 -31
- package/skills/jskit/references/patterns/server/feature-package/example/variations/InvoiceRollupProvider.js +0 -36
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<!-- Generated from `packages/agent-docs/heuristics/INDEX.md
|
|
1
|
+
<!-- Generated from `packages/agent-docs/heuristics/INDEX.md`. -->
|
|
2
2
|
|
|
3
3
|
# JSKIT Heuristics Index
|
|
4
4
|
|
|
@@ -44,3 +44,7 @@ How to use it:
|
|
|
44
44
|
- [crud-repository-mapping.md](./crud-repository-mapping.md)
|
|
45
45
|
- row policy, permission filtering, visibility before pagination, recursive CTE, descendants, package cycle, `RowPolicyPlugin`
|
|
46
46
|
- [row-policies.md](./row-policies.md)
|
|
47
|
+
- typed features, server feature, provider, service, repository, collaborator, `typeof`, `= null`, `setProvider`, `register`, `input || {}`, `payload = {}`, `async execute`, `Object.freeze`, `requires`, `optional`, `types.js`, `RuntimeKnex`, `silentLogger`, `create<Name>Actions`, `ActionSpecifications`, request context, `jskit/*` lint findings, `readable-check: allow`, `optional operation:`, `process.env`, `AppError` code, `Object.assign(new Error`, `idempotency`, `…ForTests` export, file or function size
|
|
48
|
+
- [typed-features.md](./typed-features.md)
|
|
49
|
+
- client features, composable, `use<Name>`, Vue component, client provider, props, emits, `inject`, `provide`, `ref`, `reactive`, `watch`, `addEventListener`, `setInterval`, module state, `Object.freeze` on a composable, `?.()` in a template, `jskit/typed-inject`, `jskit/collaborator-props`, `jskit/fixed-result-shape`, `jskit/released-listeners`, `jskit/no-module-state`, `jskit/no-frozen-vue-state`, `clientFeaturesConfig`, `shared resource:`
|
|
50
|
+
- [client-features.md](./client-features.md)
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
<!-- Generated from `packages/agent-docs/heuristics/client-features.md`. -->
|
|
2
|
+
|
|
3
|
+
# Client Feature Heuristics
|
|
4
|
+
|
|
5
|
+
Use when:
|
|
6
|
+
|
|
7
|
+
- writing or reviewing a composable, Vue component, client factory or client provider
|
|
8
|
+
- a `jskit/*` or `vue/*` finding from `clientFeaturesConfig` is reported
|
|
9
|
+
- a prop, injected value or option is probed, defaulted to nothing, or patched on after construction
|
|
10
|
+
|
|
11
|
+
[Client features](../client-features.md) is the one guide
|
|
12
|
+
for client code: each rule says what to do, why, and shows good and bad code.
|
|
13
|
+
Server code follows [typed features](../typed-features.md).
|
|
14
|
+
|
|
15
|
+
Simple to reason about comes first. Write plain functions and direct calls. If
|
|
16
|
+
a rule seems to need a layer, a registry, a wrapper, a computed API or a split
|
|
17
|
+
into tiny modules, the reading is wrong: take the direct form that meets the
|
|
18
|
+
rule's intent, and report the case.
|
|
19
|
+
|
|
20
|
+
## Keyword map
|
|
21
|
+
|
|
22
|
+
- a layer, wrapper, `Proxy`, `Object.fromEntries` API, one-use factory, `utils2`, `part1`, a file split only to fit a size limit
|
|
23
|
+
- [Simple to reason about](../client-features.md#simple-to-reason-about)
|
|
24
|
+
- `ReturnType<typeof useX>` repeated, an adapter shape nobody wrote down, `./client/types`, `@jskit-ai/kernel/client/types`
|
|
25
|
+
- [Client types](../client-features.md#client-types)
|
|
26
|
+
- `useX(options)` read in the body, an untyped composable option (`jskit/typed-dependencies`)
|
|
27
|
+
- [Typed options](../client-features.md#typed-options)
|
|
28
|
+
- `= null`, `= {}`, `typeof x === "function"`, `x?.()` on an option every caller passes (`jskit/required-collaborators`)
|
|
29
|
+
- [Required options](../client-features.md#required-options)
|
|
30
|
+
- `onX = () => {}`, `optional operation:`, a getter-backed binding, `?.()` in a template, `typeof source === "function" ? source() : source.value`, an upload result of several shapes
|
|
31
|
+
- [Absent options](../client-features.md#absent-options)
|
|
32
|
+
- `typeof window`, `matchMedia`, `requestAnimationFrame`, `hasWindowFunction`, `platform object:`
|
|
33
|
+
- [Platform probes](../client-features.md#platform-probes)
|
|
34
|
+
- `defineProvider` on the client, a module `Map` of components, `register<Name>()`
|
|
35
|
+
- [Client providers](../client-features.md#client-providers)
|
|
36
|
+
- `inject("key")`, `inject(KEY, null)`, `inject(KEY, {})` (`jskit/typed-inject`)
|
|
37
|
+
- [Injected values](../client-features.md#injected-values)
|
|
38
|
+
- `type: Object, default: null` on a prop the component calls, `adapter: Object` (`jskit/collaborator-props`, `vue/require-default-prop`)
|
|
39
|
+
- [Collaborator props](../client-features.md#collaborator-props)
|
|
40
|
+
- an event emitted but not declared (`vue/require-explicit-emits`)
|
|
41
|
+
- [Declared emits](../client-features.md#declared-emits)
|
|
42
|
+
- a long `<script setup>`, requests or timers in a component, `<style scoped src>`
|
|
43
|
+
- [Presenting scripts](../client-features.md#presenting-scripts)
|
|
44
|
+
- `runtime.x = …` after `useX()`, `Object.assign` onto a result, `...useX()` in a result, `Object.freeze` on a composable (`jskit/fixed-result-shape`, `jskit/no-frozen-vue-state`, `jskit/no-factory-spread`)
|
|
45
|
+
- [Fixed result shape](../client-features.md#fixed-result-shape)
|
|
46
|
+
- `watch()` moved into a helper composable while splitting
|
|
47
|
+
- [Effect order](../client-features.md#effect-order)
|
|
48
|
+
- `addEventListener` without `removeEventListener`, `setInterval`, `ResizeObserver`, `.on()` without `.off()` (`jskit/released-listeners`)
|
|
49
|
+
- [Released listeners](../client-features.md#released-listeners)
|
|
50
|
+
- a module-level `let`, `ref()` or `reactive()`, `shared resource:` (`jskit/no-module-state`)
|
|
51
|
+
- [Module state](../client-features.md#module-state)
|
|
52
|
+
- a copied `isRecord` or `normalizeText` in client code, a client copy of a server helper (`jskit/no-duplicate-helper`)
|
|
53
|
+
- [One helper per package](../client-features.md#one-helper-per-package)
|
|
54
|
+
- a `.vue` file over 750 lines (`max-lines`)
|
|
55
|
+
- [Size limits](../client-features.md#size-limits)
|
|
56
|
+
- `clientFeaturesConfig`, which globs to list, an existing application's client tree
|
|
57
|
+
- [Running the checks](../client-features.md#running-the-checks)
|
|
58
|
+
|
|
59
|
+
Avoid:
|
|
60
|
+
|
|
61
|
+
- probing a prop, option or injected value before calling it
|
|
62
|
+
- freezing a composable's result or anything holding refs
|
|
63
|
+
- patching members onto a result after it is built
|
|
64
|
+
- listeners, intervals and observers that outlive their component
|
|
65
|
+
- module-level state that is not one per page on purpose
|
|
66
|
+
- abstractions added only to satisfy a rule
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<!-- Generated from `packages/agent-docs/heuristics/crud-authoring.md
|
|
1
|
+
<!-- Generated from `packages/agent-docs/heuristics/crud-authoring.md`. -->
|
|
2
2
|
|
|
3
3
|
# CRUD authoring
|
|
4
4
|
|
|
@@ -33,13 +33,19 @@ Read these package-owned source patterns:
|
|
|
33
33
|
The migration and resource are both authored contracts. A live schema is useful
|
|
34
34
|
for understanding an imported system, but it is never the sole source of truth.
|
|
35
35
|
|
|
36
|
+
Write a field's `operations` only where it differs from the default (output,
|
|
37
|
+
create required as the field is, patch; none for `primary: true` or
|
|
38
|
+
`hidden: true`; output only for `readOnly: true`), and write a lookup field as `lookup: "<namespace>"`.
|
|
39
|
+
The `crud/resource-contract` pattern lists what each expands to.
|
|
40
|
+
|
|
36
41
|
## Ownership and access
|
|
37
42
|
|
|
38
43
|
- `public` means every record is intentionally public. It cannot be combined
|
|
39
44
|
with user or workspace ownership.
|
|
40
45
|
- `user` requires a real user ownership column and negative cross-user tests.
|
|
41
46
|
- `workspace` and `workspace_user` require an explicit workspace route/action
|
|
42
|
-
scope plus named permission policy.
|
|
47
|
+
scope plus named permission policy. The scope is workspaces-core's
|
|
48
|
+
`WORKSPACE_CRUD_SCOPE`; never copy its literal into a feature.
|
|
43
49
|
- Domain relationships such as `recipient_user_id` are not ownership merely
|
|
44
50
|
because they point to a user.
|
|
45
51
|
|
|
@@ -68,6 +74,10 @@ or rewrite a historical baseline.
|
|
|
68
74
|
- `actions` exposes non-CRUD service methods through normal validated,
|
|
69
75
|
permissioned, audited JSKIT actions and optional explicit HTTP routes.
|
|
70
76
|
|
|
77
|
+
A resource whose records carry a version number names it `lockVersionField`
|
|
78
|
+
and patches through the repository's `patchDocumentIfLockVersion`; see the
|
|
79
|
+
database layer guide's Optimistic locking.
|
|
80
|
+
|
|
71
81
|
Keep database reads and writes in repositories. Services and lifecycle hooks
|
|
72
82
|
orchestrate repositories; they do not issue raw database queries. Put external
|
|
73
83
|
side effects after commit, or write a durable outbox record inside the
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<!-- Generated from `packages/agent-docs/heuristics/crud-repository-mapping.md
|
|
1
|
+
<!-- Generated from `packages/agent-docs/heuristics/crud-repository-mapping.md`. -->
|
|
2
2
|
|
|
3
3
|
# CRUD Repository Mapping
|
|
4
4
|
|
|
@@ -61,7 +61,7 @@ remainingBatchWeight: {
|
|
|
61
61
|
- `storage: { virtual: true }` fields must not appear in create/patch write schemas
|
|
62
62
|
|
|
63
63
|
Repository pattern:
|
|
64
|
-
- build the runtime with `createCrudResourceRuntime(resource, { ... })
|
|
64
|
+
- build the runtime with `createCrudResourceRuntime(resource, knex, { ... })`, passing the application's Knex instance
|
|
65
65
|
- register computed projections in `virtualFields`
|
|
66
66
|
- keep SQL in the repository, not in shared metadata
|
|
67
67
|
- let generic CRUD runtime apply `storage.writeSerializer` during create/update writes
|
|
@@ -69,7 +69,7 @@ Repository pattern:
|
|
|
69
69
|
Example:
|
|
70
70
|
|
|
71
71
|
```js
|
|
72
|
-
const repositoryRuntime = createCrudResourceRuntime(resource, {
|
|
72
|
+
const repositoryRuntime = createCrudResourceRuntime(resource, knex, {
|
|
73
73
|
context: "receivals repository",
|
|
74
74
|
list: LIST_CONFIG,
|
|
75
75
|
virtualFields: {
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
<!-- Generated from `packages/agent-docs/heuristics/typed-features.md`. -->
|
|
2
|
+
|
|
3
|
+
# Typed Feature Heuristics
|
|
4
|
+
|
|
5
|
+
Use when:
|
|
6
|
+
|
|
7
|
+
- writing or reviewing a server feature, provider, action, service, repository, route, error or test
|
|
8
|
+
- a `jskit/*` lint rule from `@jskit-ai/config-eslint` reports a finding
|
|
9
|
+
- a collaborator is probed, defaulted to nothing, or filled in after construction
|
|
10
|
+
|
|
11
|
+
[Typed features](../typed-features.md) is the one guide:
|
|
12
|
+
each rule there says what to do, why, and shows good and bad code. This map
|
|
13
|
+
only sends a keyword or a finding to its section. Every lint message already
|
|
14
|
+
ends with the same link.
|
|
15
|
+
|
|
16
|
+
## Keyword map
|
|
17
|
+
|
|
18
|
+
- `typeof x === "function"`, `x?.method?.()`, `received?.()`, `= null`, `= {}` or `= () => {}` on a collaborator, "x is required" guard (`jskit/required-collaborators`)
|
|
19
|
+
- [Required collaborators](../typed-features.md#required-collaborators)
|
|
20
|
+
- `optional operation:` on a method every implementer has, a feature-gated operation
|
|
21
|
+
- [Required collaborators](../typed-features.md#required-collaborators)
|
|
22
|
+
- `create<Name>(dependencies)` with `dependencies.x` in the body, no `@param` type, a pure helper passed in (`jskit/typed-dependencies`)
|
|
23
|
+
- [Typed collaborators](../typed-features.md#typed-collaborators)
|
|
24
|
+
- `(...args: any[]) => Promise<any>`, `ReturnType<…>` or `X["service"]` repeated, a missing `types.js` (`jskit/named-repeated-type`)
|
|
25
|
+
- [Capability types](../typed-features.md#capability-types)
|
|
26
|
+
- `capability.service || capability`, `x?.value ?? x`, "tests pass the bare service" (`jskit/no-dual-shape`)
|
|
27
|
+
- [One shape per value](../typed-features.md#one-shape-per-value)
|
|
28
|
+
- `env = process.env`, `env || process.env`, `.env` loaded twice (`jskit/no-env-default`)
|
|
29
|
+
- [Environment from the caller](../typed-features.md#environment-from-the-caller)
|
|
30
|
+
- `setProvider`, `attach*`, any `set<Name>()` that fills a slot, `X | null` below the hook, `deferred until boot: <reason>` (`jskit/no-slot-setter`)
|
|
31
|
+
- [Optional tokens](../typed-features.md#optional-tokens)
|
|
32
|
+
- a module-level `register<Name>()`, `let x` or a `WeakMap` filled in `boot()` (`jskit/no-module-registry`)
|
|
33
|
+
- [Owned state](../typed-features.md#owned-state)
|
|
34
|
+
- `shutdown()` with `?.()` or `?? []`
|
|
35
|
+
- [Shutdown mirrors setup](../typed-features.md#shutdown-mirrors-setup)
|
|
36
|
+
- `logger = null`, `if (!logger) return`, `logger = console`, `logger?.warn`, a log line built from `error.message`
|
|
37
|
+
- [Loggers](../typed-features.md#loggers)
|
|
38
|
+
- a value built inline in `setup()`, inline `actions() { return [{ … }] }`, a `defineFeature` in `*Provider.js`
|
|
39
|
+
- [Feature files](../typed-features.md#feature-files)
|
|
40
|
+
- an action outside `create<Name>Actions`, `ActionSpecifications`, `run(service, input, context)`, positional `create<Name>Actions(service)` (`jskit/action-creator`)
|
|
41
|
+
- [Action creators](../typed-features.md#action-creators)
|
|
42
|
+
- `async execute`, `execute(input) { … }`, `await` or an envelope in an action, `input || {}`, `input?.` (`jskit/one-line-action`, `jskit/action-execute-shape`)
|
|
43
|
+
- [One-line execute](../typed-features.md#one-line-execute)
|
|
44
|
+
- `actionDefaults`, `channels` and `surfaces` repeated in every literal
|
|
45
|
+
- [Shared action fields](../typed-features.md#shared-action-fields)
|
|
46
|
+
- `mode: "patch"` on a command, a service guard that repeats `required`
|
|
47
|
+
- [Strict action inputs](../typed-features.md#strict-action-inputs)
|
|
48
|
+
- `idempotency:` (`jskit/no-idempotency`)
|
|
49
|
+
- [No idempotency](../typed-features.md#no-idempotency)
|
|
50
|
+
- a `with<Rule>(definition)` wrapper around every action
|
|
51
|
+
- [The action policy](../typed-features.md#the-action-policy)
|
|
52
|
+
- `context?.actor`, `options.context.actor`, `requireRequestContext`, `{ request, context }` beside `{ context }`
|
|
53
|
+
- [Request context](../typed-features.md#request-context)
|
|
54
|
+
- `payload = {}`, `query = {}`, `input?.x` in a service, a second parse of validated input
|
|
55
|
+
- [Validated input as is](../typed-features.md#validated-input-as-is)
|
|
56
|
+
- `options?.` or `options || {}` after `options = {}`, `fetchImpl = null` below the feature, `skip*` flags, a boolean mode parameter (`jskit/no-optional-after-default`)
|
|
57
|
+
- [Options and defaults](../typed-features.md#options-and-defaults)
|
|
58
|
+
- `return { method() { … } }` from a `create*`, an unfrozen list (`jskit/frozen-factory-result`)
|
|
59
|
+
- [Frozen results](../typed-features.md#frozen-results)
|
|
60
|
+
- `...factory(…)` in a token value or a returned API (`jskit/no-factory-spread`)
|
|
61
|
+
- [Named members](../typed-features.md#named-members)
|
|
62
|
+
- a copied helper, function or arrow, a local `normalizeText` (`jskit/no-duplicate-helper`)
|
|
63
|
+
- [One helper per package](../typed-features.md#one-helper-per-package)
|
|
64
|
+
- `options?.trx || options?.transaction`, a hand-read actor, cursor or created id
|
|
65
|
+
- [One reader per fact](../typed-features.md#one-reader-per-fact)
|
|
66
|
+
- a route that queries storage, `boot*.js` holding routes
|
|
67
|
+
- [Routes](../typed-features.md#routes)
|
|
68
|
+
- `new AppError(status, message)` with no code, `new NotFoundError("…")`, one code for two sentences (`jskit/app-error-code`)
|
|
69
|
+
- [Refusals carry their own code](../typed-features.md#refusals-carry-their-own-code)
|
|
70
|
+
- `AppError(500, …)` for an internal invariant
|
|
71
|
+
- [Internal failures are plain errors](../typed-features.md#internal-failures-are-plain-errors)
|
|
72
|
+
- `Object.assign(new Error(…), { statusCode })`, `error.status = 404` (`jskit/no-patched-error`)
|
|
73
|
+
- [One construction per error](../typed-features.md#one-construction-per-error)
|
|
74
|
+
- `.catch(() => {})` around a collaborator call
|
|
75
|
+
- [Failures are logged, not swallowed](../typed-features.md#failures-are-logged-not-swallowed)
|
|
76
|
+
- a double that copies an id format or a stream frame, production code shaped around a double
|
|
77
|
+
- [Doubles use documented seams](../typed-features.md#doubles-use-documented-seams)
|
|
78
|
+
- a parameter, option or default only tests pass
|
|
79
|
+
- [Tests are not callers](../typed-features.md#tests-are-not-callers)
|
|
80
|
+
- `…ForTests`, `__reset…`, `testOnly…` exports (`jskit/no-test-only-export`)
|
|
81
|
+
- [No test-only exports](../typed-features.md#no-test-only-exports)
|
|
82
|
+
- a file over 750 lines, a function over 600 (`max-lines`, `max-lines-per-function`), a data module
|
|
83
|
+
- [Size limits](../typed-features.md#size-limits), [Data modules](../typed-features.md#data-modules)
|
|
84
|
+
- two properties on one line in `Object.freeze({ … })` or a token map (`jskit/one-property-per-line`)
|
|
85
|
+
- [Formatter](../typed-features.md#formatter)
|
|
86
|
+
- `build*` factories, `create*` pure builders, files not named for what they hold
|
|
87
|
+
- [Names](../typed-features.md#names)
|
|
88
|
+
- a `//` description before a `/** */` block, a comment that says "was", "now", "until" or "tests" (`jskit/jsdoc-description-inside`)
|
|
89
|
+
- [Comments](../typed-features.md#comments)
|
|
90
|
+
- `readable-check: allow` without a reason prefix, a reason that cites tests (`jskit/allow-comment-form`)
|
|
91
|
+
- [Exceptions](../typed-features.md#exceptions)
|
|
92
|
+
|
|
93
|
+
Avoid:
|
|
94
|
+
|
|
95
|
+
- probing a collaborator before calling it
|
|
96
|
+
- defaulting a collaborator to `null`, `{}` or a no-op
|
|
97
|
+
- setters that fill a slot after construction
|
|
98
|
+
- module-level registries
|
|
99
|
+
- refusals without their own code
|
|
100
|
+
- excusing a finding without a reason in its `readable-check: allow` comment
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<!-- Generated from `packages/agent-docs/heuristics/ui-testing.md
|
|
1
|
+
<!-- Generated from `packages/agent-docs/heuristics/ui-testing.md`. -->
|
|
2
2
|
|
|
3
3
|
# UI Testing Pattern
|
|
4
4
|
|
|
@@ -26,7 +26,7 @@ Rules:
|
|
|
26
26
|
reach the form before reload, then assert the original list URL; direct entry
|
|
27
27
|
checks the configured fallback separately. Do not replace this wait with sleeps.
|
|
28
28
|
- A managed runner supplies `PLAYWRIGHT_BASE_URL`. When it is set, JSKIT does not start another app server.
|
|
29
|
-
-
|
|
29
|
+
- A managed runner may supply an authenticated context through `PLAYWRIGHT_STORAGE_STATE`. Treat that file as a temporary secret: do not commit it, print it, or retain it after the run.
|
|
30
30
|
- Do not install a browser when the environment provides a managed browser runner.
|
|
31
31
|
- Shared CRUD lists retain both card and table markup and hide the inactive
|
|
32
32
|
layout with CSS. Select visible record text with
|
|
@@ -134,7 +134,7 @@ A managed preview must not expose `AUTH_DEV_BYPASS_SECRET` to project code or fo
|
|
|
134
134
|
|
|
135
135
|
```bash
|
|
136
136
|
PLAYWRIGHT_BASE_URL=https://managed-preview.example.test \
|
|
137
|
-
|
|
137
|
+
PLAYWRIGHT_STORAGE_STATE=/secure/temp/playwright-state.json \
|
|
138
138
|
playwright test tests/e2e/contacts.spec.ts
|
|
139
139
|
```
|
|
140
140
|
|
|
@@ -152,7 +152,7 @@ test into a successful command. For an unmanaged project, for example:
|
|
|
152
152
|
npx playwright test tests/e2e/contacts.spec.ts -g filters --reporter=dot > /tmp/contacts-test.log 2>&1
|
|
153
153
|
```
|
|
154
154
|
|
|
155
|
-
On
|
|
155
|
+
On a managed host, run the host's launcher for the declared test target
|
|
156
156
|
with the same file/case selection and output redirection. Do not replace the
|
|
157
157
|
managed launcher with the unmanaged example.
|
|
158
158
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<!-- Generated from `packages/agent-docs/site/guide/framework/material-3.md
|
|
1
|
+
<!-- Generated from `packages/agent-docs/site/guide/framework/material-3.md`. -->
|
|
2
2
|
|
|
3
3
|
# Material 3
|
|
4
4
|
|
|
@@ -97,7 +97,7 @@ Run this behavior-preserving audit over every affected screen:
|
|
|
97
97
|
3. Check hierarchy, token use, component purpose, responsive presentation,
|
|
98
98
|
interaction states, keyboard/focus behavior, labels, targets, contrast, and
|
|
99
99
|
reduced motion.
|
|
100
|
-
4. Audit Back on every affected page using [Back navigation](
|
|
100
|
+
4. Audit Back on every affected page using [Back navigation](ui-operations.md#back-navigation):
|
|
101
101
|
verify its presence or justified omission, actual previous-page destination,
|
|
102
102
|
safe direct-entry fallback, and retained origin context. Inspect handlers and
|
|
103
103
|
route bindings; a hardcoded parent/list link is an explicit exception, not
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<!-- Generated from `packages/agent-docs/site/guide/app-setup/multi-homing.md
|
|
1
|
+
<!-- Generated from `packages/agent-docs/site/guide/app-setup/multi-homing.md`. -->
|
|
2
2
|
|
|
3
3
|
# Workspace tenancy
|
|
4
4
|
|
|
@@ -58,13 +58,32 @@ config.tenancyPolicy = {
|
|
|
58
58
|
Provisioning runs in the users profile-sync lifecycle after registration and
|
|
59
59
|
sign-in. The first run creates the personal workspace, its owner membership and
|
|
60
60
|
its settings; later runs reuse it. The default name is the user's display name,
|
|
61
|
-
or email, followed by "'s Workspace".
|
|
62
|
-
`
|
|
63
|
-
(`id`, `displayName`, `email`, `username`), and
|
|
61
|
+
or email, followed by "'s Workspace". To choose another, provide the
|
|
62
|
+
`workspaces.personal-workspace-name` capability from an application feature. It
|
|
63
|
+
receives the synchronized profile (`id`, `displayName`, `email`, `username`), and
|
|
64
|
+
an empty result keeps the default:
|
|
64
65
|
|
|
65
66
|
```js
|
|
66
|
-
|
|
67
|
-
|
|
67
|
+
import { defineFeature } from "@jskit-ai/kernel/server/features";
|
|
68
|
+
import { homeWorkspaceName } from "./homeWorkspaceName.js";
|
|
69
|
+
|
|
70
|
+
const AppPersonalWorkspaceNameFeature = defineFeature({
|
|
71
|
+
id: "app.personal-workspace-name",
|
|
72
|
+
provides: {
|
|
73
|
+
personalWorkspaceName: "workspaces.personal-workspace-name"
|
|
74
|
+
},
|
|
75
|
+
setup: () => ({ personalWorkspaceName: homeWorkspaceName })
|
|
76
|
+
});
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
```js
|
|
80
|
+
// homeWorkspaceName.js
|
|
81
|
+
/** @type {import("@jskit-ai/workspaces-core/server/types").PersonalWorkspaceName} */
|
|
82
|
+
function homeWorkspaceName(user) {
|
|
83
|
+
return `${user.displayName || user.email}'s home`;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export { homeWorkspaceName };
|
|
68
87
|
```
|
|
69
88
|
|
|
70
89
|
### Development sign-in
|
|
@@ -103,8 +122,13 @@ before an operation discloses records or record existence.
|
|
|
103
122
|
|
|
104
123
|
For a standard CRUD resource owned by a workspace, give its table the
|
|
105
124
|
`workspace_id` column, set the resource's `autofilter: "workspace"`, and bind
|
|
106
|
-
`defineCrudJsonApiFeature()` with `ownershipFilter: "workspace"`
|
|
107
|
-
|
|
125
|
+
`defineCrudJsonApiFeature()` with `ownershipFilter: "workspace"` and `scope:
|
|
126
|
+
WORKSPACE_CRUD_SCOPE` (from `@jskit-ai/workspaces-core/server/support/workspaceCrud`)
|
|
127
|
+
on a workspace surface. JSKIT then filters `workspaceId` by the workspace in the
|
|
128
|
+
route. A repository method you add reads the workspace id with
|
|
129
|
+
`resolveWorkspaceScopeValue(options.context)`
|
|
130
|
+
(`@jskit-ai/json-rest-api-core/server/jsonRestApiHost`), which throws when the
|
|
131
|
+
context names two workspaces.
|
|
108
132
|
`workspace_user` also filters by the signed-in user. See the CRUD operations
|
|
109
133
|
guide.
|
|
110
134
|
|
|
@@ -152,14 +176,31 @@ capability provides:
|
|
|
152
176
|
|
|
153
177
|
### Invitation email
|
|
154
178
|
|
|
155
|
-
To send invitation email,
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
message
|
|
162
|
-
|
|
179
|
+
To send invitation email, provide the optional `workspaces.invite-mailer`
|
|
180
|
+
capability from one of the application's providers. Without one, invitations
|
|
181
|
+
are still created and delivery reports `mailer_unconfigured`. The mailer, typed
|
|
182
|
+
`WorkspaceInviteMailer` in `@jskit-ai/workspaces-core/server/types`, is an
|
|
183
|
+
object whose `sendWorkspaceInvite(message, options)` receives `{ email,
|
|
184
|
+
inviteUrl, workspace, inviter, roleSid, expiresAt, message }`, where the inner
|
|
185
|
+
`message` is the rendered `{ subject, text, html }`:
|
|
186
|
+
|
|
187
|
+
```js
|
|
188
|
+
const InviteMailerProvider = defineProvider({
|
|
189
|
+
id: "app.invite-mailer",
|
|
190
|
+
provides: {
|
|
191
|
+
inviteMailer: "workspaces.invite-mailer"
|
|
192
|
+
},
|
|
193
|
+
setup() {
|
|
194
|
+
return { inviteMailer: createAppInviteMailer() };
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
The optional `workspaces.invite-email-template` capability is a function that
|
|
200
|
+
renders that inner message; it receives `{ email, inviteUrl, workspace, inviter,
|
|
201
|
+
roleSid, roleLabel, expiresAt, locale, t }` (`roleLabel` only when configured).
|
|
202
|
+
Provide it from an application feature, as for the mailer; without it the
|
|
203
|
+
built-in template renders the message. Invitation links use `/invite/:token` unless
|
|
163
204
|
`workspaceInvitations.invitePath` names another path. The
|
|
164
205
|
`workspaces/workspace-server` pattern includes an example renderer.
|
|
165
206
|
|
|
@@ -252,8 +293,8 @@ authorization and role checks. Do not pass arbitrary HTTP input as options.
|
|
|
252
293
|
| `workspaces.repositories.workspaceInvites.lockWorkspaceForInvitations(workspaceId, { trx })` | Locks the workspace before application receipt/draft rows when composing preparation. Requires an active transaction. |
|
|
253
294
|
| `workspaces.services.members.prepareInvite(workspace, actor, payload, options)` | Requires a managed `options.trx`. Validates the invitation role, replaces pending invitations for that workspace/email, and returns `{ createdInviteId, inviteTokenPreview }`. Never sends. |
|
|
254
295
|
| `workspaces.services.members.sendInvite(workspace, actor, prepared, options)` | Requires no `options.trx`. Reloads the committed pending invitation and workspace display data, validates expiry and token correspondence, and sends that invitation without replacement. |
|
|
255
|
-
| `workspaces.services.members.createInvite(workspace, actor, payload, options)` | Owns preparation and commit, then calls `sendInvite
|
|
256
|
-
| `workspaces.
|
|
296
|
+
| `workspaces.services.members.createInvite(workspace, actor, payload, options)` | Owns preparation and commit, then calls `sendInvite`, and answers with `sendInvite`'s result as JSON:API data (`returnJsonApiData`, read it from `.value`), as the invite action sends it. Rejects `options.trx`. |
|
|
297
|
+
| `workspaces.invite-acceptance-participant` (optional capability) | One application function receiving `({ invite, user }, options)` inside the acceptance transaction. Without it, acceptance activates the membership only. |
|
|
257
298
|
|
|
258
299
|
`sendInvite` accepts `{ createdInviteId, inviteTokenPreview }` from preparation or
|
|
259
300
|
only `{ createdInviteId }` for a later attempt. The latter uses JSKIT's existing
|
|
@@ -266,30 +307,34 @@ diagnostics and administrative receipts; save the invitation ID in the receipt.
|
|
|
266
307
|
|
|
267
308
|
### Preparation, association, commit and controlled delivery
|
|
268
309
|
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
310
|
+
The acceptance participant comes from a small application feature that provides
|
|
311
|
+
`workspaces.invite-acceptance-participant` and requires only what its writes need.
|
|
312
|
+
It cannot require `workspaces.core`, which receives it. In this example,
|
|
313
|
+
`reviewedPeople`, `people`, `scopes` and `audit` are application services. Each
|
|
314
|
+
forwards the supplied transaction to its repositories.
|
|
272
315
|
|
|
273
316
|
```js
|
|
274
|
-
//
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
});
|
|
317
|
+
// An application feature providing "workspaces.invite-acceptance-participant":
|
|
318
|
+
setup: ({ reviewedPeople, people, scopes, audit }) => ({
|
|
319
|
+
inviteAcceptanceParticipant: async ({ invite, user }, options) => {
|
|
320
|
+
// Resolve from the exact validated invitation, never a client person ID.
|
|
321
|
+
const association = await reviewedPeople.resolveInvitation(invite.id, options);
|
|
322
|
+
if (association.kind === "ordinary") return;
|
|
323
|
+
await reviewedPeople.requireCurrentReview(association, {
|
|
324
|
+
workspaceId: invite.workspaceId,
|
|
325
|
+
user,
|
|
326
|
+
roleSid: invite.roleSid
|
|
327
|
+
}, options);
|
|
328
|
+
await people.linkAccountAndTraining(association.personId, user.id, options);
|
|
329
|
+
await scopes.applyReviewedAccess(association, user.id, options);
|
|
330
|
+
await audit.recordInvitationAcceptance(association, user.id, options);
|
|
331
|
+
}
|
|
332
|
+
})
|
|
291
333
|
|
|
292
|
-
// Inside an authorized application command
|
|
334
|
+
// Inside an authorized application command, in a feature that requires
|
|
335
|
+
// workspaces: "workspaces.core":
|
|
336
|
+
const { members } = workspaces.services;
|
|
337
|
+
const invites = workspaces.repositories.workspaceInvites;
|
|
293
338
|
const prepared = await invites.withTransaction(async (trx) => {
|
|
294
339
|
const options = { trx, context };
|
|
295
340
|
// Match acceptance's order: workspace, then application draft/receipt rows.
|
|
@@ -316,23 +361,24 @@ invitation. Association failure rolls back the new invitation, replacement of
|
|
|
316
361
|
the previous invitation, receipt and application writes. Send only after the
|
|
317
362
|
transaction resolves successfully.
|
|
318
363
|
|
|
319
|
-
With no `
|
|
320
|
-
an explanatory `message` and an empty
|
|
321
|
-
committed.
|
|
364
|
+
With no provider of `workspaces.invite-mailer`, delivery returns
|
|
365
|
+
`status: "mailer_unconfigured"`, an explanatory `message` and an empty
|
|
366
|
+
`providerMessageId`; the invitation remains committed. Provide a controlled
|
|
367
|
+
mailer in tests; SMTP is unnecessary:
|
|
322
368
|
|
|
323
369
|
```js
|
|
324
|
-
|
|
370
|
+
const inviteMailer = {
|
|
325
371
|
async sendWorkspaceInvite(message) {
|
|
326
372
|
capturedInvites.push(message); // Test-local memory; contains the secret link.
|
|
327
373
|
return { status: "sent", message: "Captured by test mailer.", providerMessageId: "fixture-1" };
|
|
328
374
|
}
|
|
329
|
-
}
|
|
375
|
+
};
|
|
330
376
|
```
|
|
331
377
|
|
|
332
378
|
Renderer/mailer exceptions return `inviteDelivery.status: "failed"` with a fixed
|
|
333
379
|
message to keep provider errors from exposing tokens. Persistence is unchanged.
|
|
334
|
-
Successful mailer results retain their normalized status, message
|
|
335
|
-
message ID; the default status is `sent`.
|
|
380
|
+
Successful mailer results retain their normalized status, message, message
|
|
381
|
+
code and provider message ID; the default status is `sent`.
|
|
336
382
|
|
|
337
383
|
A provider may accept a message before throwing or losing its response. The
|
|
338
384
|
application must track delivery attempts and decide when to retry; email is not
|
|
@@ -377,7 +423,7 @@ Preserve `error.transactionOutcome` and `error.cause`: `rolledBack` confirms
|
|
|
377
423
|
rollback, `committed` can accompany a failed completion hook, and `unknown`
|
|
378
424
|
requires resolving the outcome before retrying. Errors after commit cannot undo
|
|
379
425
|
persistence. See
|
|
380
|
-
[managed transaction guidance](
|
|
426
|
+
[managed transaction guidance](existing-application-migration.md#json-rest-v2-integration).
|
|
381
427
|
|
|
382
428
|
Invitation mutations lock workspace before invitation rows. A losing acceptance,
|
|
383
429
|
refusal, revocation or replacement cannot overwrite accepted/revoked state.
|
|
@@ -411,9 +457,9 @@ npm run verify
|
|
|
411
457
|
```
|
|
412
458
|
|
|
413
459
|
Run the application's `npm run jskit:update`, restart its backend and verify that
|
|
414
|
-
`members.prepareInvite
|
|
415
|
-
`
|
|
416
|
-
`workspaces.
|
|
460
|
+
`members.prepareInvite` and `members.sendInvite` are functions on the installed
|
|
461
|
+
`workspaces.core` capability, and that the application feature providing
|
|
462
|
+
`workspaces.invite-acceptance-participant` is installed. The first release containing this contract pairs
|
|
417
463
|
`@jskit-ai/workspaces-core@0.1.198`, `@jskit-ai/jskit-catalog@0.1.245` and
|
|
418
464
|
`@jskit-ai/agent-docs@0.1.192`. Upgrade the coordinated dependency graph, then run
|
|
419
465
|
the application's identity, training, permission, privacy and browser tests.
|