@jskit-ai/agent-docs 0.1.261 → 0.1.263
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 +5 -2
- package/guide/agent/app-extras/realtime.md +5 -0
- package/guide/agent/framework/client-features.md +63 -1
- package/package.json +1 -1
- package/patterns/feature-package/example/booking-engine/package.json +1 -1
- package/patterns/minimal-foundation/example/package.json +4 -4
- package/patterns/shell-foundation/example/package.json +5 -5
- package/patterns/shell-foundation/example/packages/main/package.json +1 -1
- package/reference/autogen/PATTERN_INDEX.md +37 -37
- package/reference/autogen/packages/assistant-core.md +4 -1
- package/reference/autogen/packages/assistant-runtime.md +1 -0
- package/reference/autogen/packages/auth-web.md +63 -28
- package/reference/autogen/packages/connectors-catalog.md +2 -2
- package/reference/autogen/packages/connectors-web.md +13 -9
- package/reference/autogen/packages/http-runtime.md +6 -1
- package/reference/autogen/packages/http-web.md +127 -54
- package/reference/autogen/packages/kernel.md +25 -12
- package/reference/autogen/packages/mobile-capacitor.md +36 -9
- package/reference/autogen/packages/realtime.md +17 -6
- package/reference/autogen/packages/rewarded-web.md +9 -4
- package/reference/autogen/packages/shell-web.md +115 -80
- package/reference/autogen/packages/uploads-image-web.md +35 -8
- package/reference/autogen/packages/users-web.md +38 -2
- package/reference/autogen/packages/workspaces-web.md +96 -55
- package/reference/autogen/tooling/config-eslint.md +1 -0
- package/reference/autogen/tooling/jskit-release.md +1 -1
- package/skills/jskit/references/client-features.md +63 -1
- package/skills/jskit/references/heuristics/client-features.md +4 -0
- package/skills/jskit/references/pattern-index.md +37 -37
- package/skills/jskit/references/patterns/app/minimal-foundation/example/package.json +4 -4
- package/skills/jskit/references/patterns/app/shell-foundation/example/package.json +5 -5
- package/skills/jskit/references/patterns/app/shell-foundation/example/packages/main/package.json +1 -1
- package/skills/jskit/references/patterns/auth/accounts-hub/example/package.json +2 -2
- 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/calendar-cli/example/package.json +4 -4
- package/skills/jskit/references/patterns/crud/json-api-resource-package/example/packages/books/package.json +2 -2
- package/skills/jskit/references/patterns/database/mysql-application/example/package.json +1 -1
- package/skills/jskit/references/patterns/database/postgres-application/example/package.json +1 -1
- package/skills/jskit/references/patterns/realtime/realtime-application/example/package.json +2 -2
- package/skills/jskit/references/patterns/rewards/google-rewarded/example/googlePublisherTag.js +13 -10
- package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/package.json +1 -1
- package/skills/jskit/references/patterns/ui/page-and-placement/example/src/placementTopology.js +1 -0
- package/skills/jskit/references/patterns/users/account-settings/example/src/components/account/settings/AccountSettingsPreferencesSection.vue +7 -7
- package/skills/jskit/references/patterns/users/account-settings/example/src/components/account/settings/AccountSettingsProfileSection.vue +1 -1
- package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users/package.json +2 -2
- package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users-workspace/package.json +3 -3
- package/skills/jskit/references/patterns/workspaces/workspace-surfaces/example/src/composables/useWorkspaceNotFoundState.js +2 -2
|
@@ -16,13 +16,21 @@ Use this on demand; do not load the full index at startup.
|
|
|
16
16
|
|
|
17
17
|
### `src/client/account-settings/accountSettingsInvitesRuntime.js`
|
|
18
18
|
Exports
|
|
19
|
-
- `createAccountSettingsInvitesRuntime({ invitesAvailable, isResolvingInvite, inviteAction, redeemInviteModel, redeemInviteCommand, pendingInvites, pendingInvitesModel, pendingInvitesView, openWorkspace, reportAccountFeedback }
|
|
19
|
+
- `createAccountSettingsInvitesRuntime({ invitesAvailable, isResolvingInvite, inviteAction, redeemInviteModel, redeemInviteCommand, pendingInvites, pendingInvitesModel, pendingInvitesView, openWorkspace, reportAccountFeedback })`
|
|
20
20
|
|
|
21
21
|
### `src/client/account-settings/useAccountSettingsInvitesSectionRuntime.js`
|
|
22
22
|
Exports
|
|
23
23
|
- `useAccountSettingsInvitesSectionRuntime()`
|
|
24
|
+
|
|
25
|
+
### `src/client/browser.js`
|
|
26
|
+
Exports
|
|
27
|
+
- `assignPageLocation(href)`
|
|
28
|
+
- `pageClipboard()`
|
|
29
|
+
- `pageLocalStorage()`
|
|
30
|
+
- `pagePathname()`
|
|
31
|
+
- `pagePrefersDark()`
|
|
24
32
|
Local functions
|
|
25
|
-
- `
|
|
33
|
+
- `pageWindow()`
|
|
26
34
|
|
|
27
35
|
### `src/client/components/AccountSettingsInvitesSection.vue`
|
|
28
36
|
Exports
|
|
@@ -56,25 +64,6 @@ Local functions
|
|
|
56
64
|
### `src/client/components/WorkspaceMembersClientElement.vue`
|
|
57
65
|
Exports
|
|
58
66
|
- None
|
|
59
|
-
Local functions
|
|
60
|
-
- `workspaceMembersPath(memberId)`
|
|
61
|
-
- `workspaceInvitePath(inviteId)`
|
|
62
|
-
- `resetMessages()`
|
|
63
|
-
- `clearRoleOptions()`
|
|
64
|
-
- `resetViewState()`
|
|
65
|
-
- `toRoleTitle(roleSid)`
|
|
66
|
-
- `normalizeRoleCatalog(payload = {})`
|
|
67
|
-
- `applyRoleCatalog(payload = {})`
|
|
68
|
-
- `normalizeMembers(entries)`
|
|
69
|
-
- `normalizeInvites(entries)`
|
|
70
|
-
- `latestPage(pages)`
|
|
71
|
-
- `applyWorkspaceSettingsPolicy(payload = {})`
|
|
72
|
-
- `refreshLoad()`
|
|
73
|
-
- `submitInvite()`
|
|
74
|
-
- `copyCreatedInviteLink()`
|
|
75
|
-
- `submitRevokeInvite(inviteId)`
|
|
76
|
-
- `submitMemberRoleUpdate(member, roleSid)`
|
|
77
|
-
- `submitRemoveMember(member)`
|
|
78
67
|
|
|
79
68
|
### `src/client/components/WorkspaceMembersMenuItem.vue`
|
|
80
69
|
Exports
|
|
@@ -94,25 +83,14 @@ Exports
|
|
|
94
83
|
Exports
|
|
95
84
|
- None
|
|
96
85
|
Local functions
|
|
97
|
-
- `normalizePendingInvite(entry)`
|
|
98
|
-
- `reportFeedback({ message, severity = "error", channel = "", dedupeKey = "" } = {})`
|
|
99
86
|
- `workspaceInitials(workspace)`
|
|
100
|
-
- `workspaceHomePath(workspaceSlug)`
|
|
101
|
-
- `resolveLandingSlug()`
|
|
102
87
|
- `workspaceOpenLabel(workspace)`
|
|
103
88
|
- `isRespondingToInvite(invite, decision)`
|
|
104
|
-
- `openWorkspace(workspaceSlug)`
|
|
105
|
-
- `respondToInvite(invite, decision)`
|
|
106
|
-
- `acceptInvite(invite)`
|
|
107
|
-
- `refuseInvite(invite)`
|
|
108
|
-
- `createWorkspace()`
|
|
109
|
-
- `refreshBootstrap()`
|
|
110
89
|
|
|
111
90
|
### `src/client/components/WorkspaceSelector.vue`
|
|
112
91
|
Exports
|
|
113
92
|
- None
|
|
114
93
|
Local functions
|
|
115
|
-
- `resolveBrowserPath()`
|
|
116
94
|
- `navigateToWorkspace(slug)`
|
|
117
95
|
|
|
118
96
|
### `src/client/components/WorkspaceSettingsMenuItem.vue`
|
|
@@ -123,15 +101,27 @@ Exports
|
|
|
123
101
|
Exports
|
|
124
102
|
- None
|
|
125
103
|
|
|
104
|
+
### `src/client/composables/useWorkspaceMembersActions.js`
|
|
105
|
+
Exports
|
|
106
|
+
- `useWorkspaceMembersActions({ forms, workspaceMembersApiPath, workspaceInvitesApiPath, canInviteMembers, canManageMembers, canRevokeInvites, workspaceRolesView, workspaceMembersList, workspaceInvitesList })`
|
|
107
|
+
|
|
108
|
+
### `src/client/composables/useWorkspaceMembersPage.js`
|
|
109
|
+
Exports
|
|
110
|
+
- `useWorkspaceMembersPage()`
|
|
111
|
+
|
|
126
112
|
### `src/client/composables/useWorkspaceRouteContext.js`
|
|
127
113
|
Exports
|
|
128
114
|
- `useWorkspaceRouteContext()`
|
|
129
115
|
|
|
116
|
+
### `src/client/composables/useWorkspacesLanding.js`
|
|
117
|
+
Exports
|
|
118
|
+
- `useWorkspacesLanding()`
|
|
119
|
+
|
|
130
120
|
### `src/client/composables/useWorkspaceSurfaceId.js`
|
|
131
121
|
Exports
|
|
132
|
-
- `useWorkspaceSurfaceId({ route
|
|
122
|
+
- `useWorkspaceSurfaceId({ route, placementContext })`
|
|
133
123
|
Local functions
|
|
134
|
-
- `resolveCurrentPathname(route
|
|
124
|
+
- `resolveCurrentPathname(route)`
|
|
135
125
|
|
|
136
126
|
### `src/client/i18n.js`
|
|
137
127
|
Exports
|
|
@@ -150,23 +140,26 @@ Exports
|
|
|
150
140
|
- `findWorkspaceBySlug(entries = [], workspaceSlug = "")`
|
|
151
141
|
- `normalizeWorkspaceEntry(entry = null)`
|
|
152
142
|
- `normalizeWorkspaceList(entries = [])`
|
|
153
|
-
Local functions
|
|
154
|
-
- `normalizeWorkspaceSlug(value = "")`
|
|
155
143
|
|
|
156
144
|
### `src/client/lib/lastWorkspace.js`
|
|
157
145
|
Exports
|
|
158
|
-
- `readLastWorkspaceSlug(userId, { storage } = {})`
|
|
146
|
+
- `readLastWorkspaceSlug(userId, { storage = pageLocalStorage() } = {})`
|
|
159
147
|
- `resolveWorkspaceLandingSlug({ workspaces = [], pendingInvites = [], lastWorkspaceSlug = "" } = {})`
|
|
160
|
-
- `writeLastWorkspaceSlug(userId, workspaceSlug, { storage } = {})`
|
|
148
|
+
- `writeLastWorkspaceSlug(userId, workspaceSlug, { storage = pageLocalStorage() } = {})`
|
|
161
149
|
Local functions
|
|
162
|
-
- `resolveStorage(storage)`
|
|
163
150
|
- `lastWorkspaceStorageKey(userId)`
|
|
164
151
|
|
|
152
|
+
### `src/client/lib/pendingInvites.js`
|
|
153
|
+
Exports
|
|
154
|
+
- `readPendingInvites(payload, invitesEnabled)`
|
|
155
|
+
Local functions
|
|
156
|
+
- `normalizePendingInvite(entry)`
|
|
157
|
+
|
|
165
158
|
### `src/client/lib/profileSurfaceMenuLinks.js`
|
|
166
159
|
Exports
|
|
167
|
-
- `resolveProfileSurfaceMenuLinks({ context, surface }
|
|
168
|
-
- `resolvePrimarySurfaceSwitchLink({ context, surface }
|
|
169
|
-
- `resolveSurfaceSwitchLinks({ context, surface }
|
|
160
|
+
- `resolveProfileSurfaceMenuLinks({ context, surface })`
|
|
161
|
+
- `resolvePrimarySurfaceSwitchLink({ context, surface })`
|
|
162
|
+
- `resolveSurfaceSwitchLinks({ context, surface })`
|
|
170
163
|
- `hasWorkspaceMembership`
|
|
171
164
|
Local functions
|
|
172
165
|
- `resolveSurfaceSwitchIcon(surfaceId = "", explicitIcon = "")`
|
|
@@ -180,8 +173,6 @@ Exports
|
|
|
180
173
|
- `resolveSurfaceAccessPolicy(contextValue = null, surfaceDefinition = null)`
|
|
181
174
|
- `evaluateSurfaceAccess({ context = null, surfaceId = "", workspaceSlug = "", allowOnUnknown = false } = {})`
|
|
182
175
|
Local functions
|
|
183
|
-
- `normalizeSurfaceAccessPolicyId(value = "")`
|
|
184
|
-
- `normalizeWorkspaceSlug(value = "")`
|
|
185
176
|
- `normalizeAccessFlagName(value = "")`
|
|
186
177
|
- `normalizeStringList(value)`
|
|
187
178
|
- `normalizeSurfaceAccessFlags(value = null)`
|
|
@@ -199,8 +190,8 @@ Exports
|
|
|
199
190
|
- `hexColorToRgb(value = "")`
|
|
200
191
|
- `normalizeThemePreference(value)`
|
|
201
192
|
- `persistBootstrapThemePreference(payload = {}, options = {})`
|
|
202
|
-
- `persistThemePreference(themePreference,
|
|
203
|
-
- `readPersistedThemePreference(
|
|
193
|
+
- `persistThemePreference(themePreference, { storage = pageLocalStorage() } = {})`
|
|
194
|
+
- `readPersistedThemePreference({ storage = pageLocalStorage() } = {})`
|
|
204
195
|
- `resolveBootstrapThemePreference(payload = {}, options = {})`
|
|
205
196
|
- `resolveThemeNameForPreference(themePreference, options = {})`
|
|
206
197
|
- `resolveBootstrapThemeName(payload = {}, options = {})`
|
|
@@ -209,7 +200,6 @@ Exports
|
|
|
209
200
|
- `setVuetifyThemeName(themeController, themeName)`
|
|
210
201
|
Local functions
|
|
211
202
|
- `resolveSystemThemeName({ prefersDark } = {})`
|
|
212
|
-
- `resolveThemePreferenceStorage(options = {})`
|
|
213
203
|
- `normalizeHexColor(value = "")`
|
|
214
204
|
- `resolveVuetifyThemeDefinitions(themeController)`
|
|
215
205
|
- `normalizeThemeColors(colors)`
|
|
@@ -227,6 +217,15 @@ Local functions
|
|
|
227
217
|
- `resolveSurfaceBasePath(context = null, surface = "")`
|
|
228
218
|
- `resolveWorkspaceBasePath(context = null, surface = "", workspaceSlug = "")`
|
|
229
219
|
|
|
220
|
+
### `src/client/lib/workspaceMembersPayloads.js`
|
|
221
|
+
Exports
|
|
222
|
+
- `latestPage(pages)`
|
|
223
|
+
- `normalizeInvites(entries)`
|
|
224
|
+
- `normalizeMembers(entries)`
|
|
225
|
+
- `normalizeRoleCatalog(payload)`
|
|
226
|
+
Local functions
|
|
227
|
+
- `toRoleTitle(roleSid)`
|
|
228
|
+
|
|
230
229
|
### `src/client/lib/workspaceSurfaceContext.js`
|
|
231
230
|
Exports
|
|
232
231
|
- `listWorkspaceSurfaceIdsFromSurfaceConfig(surfaceConfig = null)`
|
|
@@ -253,7 +252,10 @@ Exports
|
|
|
253
252
|
|
|
254
253
|
### `src/client/runtime/bootstrapPlacementRouteGuards.js`
|
|
255
254
|
Exports
|
|
256
|
-
- `createBootstrapPlacementRouteGuards({ placementRuntime, router
|
|
255
|
+
- `createBootstrapPlacementRouteGuards({ placementRuntime, router, root, getWorkspaceBootstrapStatus })`
|
|
256
|
+
Local functions
|
|
257
|
+
- `allowEveryRoute()`
|
|
258
|
+
- `normalizeGuardEvaluator(candidate)`
|
|
257
259
|
|
|
258
260
|
### `src/client/runtime/bootstrapPlacementRuntime.js`
|
|
259
261
|
Exports
|
|
@@ -262,7 +264,7 @@ Exports
|
|
|
262
264
|
- `WORKSPACE_BOOTSTRAP_STATUS_FORBIDDEN`
|
|
263
265
|
- `WORKSPACE_BOOTSTRAP_STATUS_UNAUTHENTICATED`
|
|
264
266
|
- `WORKSPACE_BOOTSTRAP_STATUS_ERROR`
|
|
265
|
-
- `createBootstrapPlacementRuntime({ bootstrapRuntime, placementRuntime, realtime
|
|
267
|
+
- `createBootstrapPlacementRuntime({ bootstrapRuntime, placementRuntime, realtime, router, vueApp, logger })`
|
|
266
268
|
|
|
267
269
|
### `src/client/runtime/bootstrapPlacementRuntimeConstants.js`
|
|
268
270
|
Exports
|
|
@@ -283,20 +285,18 @@ Exports
|
|
|
283
285
|
- `isGuardDenied(outcome)`
|
|
284
286
|
- `normalizeSearch(search = "")`
|
|
285
287
|
- `normalizeWorkspaceBootstrapStatus(status = "")`
|
|
286
|
-
- `
|
|
287
|
-
- `
|
|
288
|
-
- `resolveRequestedWorkspaceBootstrapStatus(payload = {}, workspaceSlug = "")`
|
|
288
|
+
- `resolveAuthSignature(context)`
|
|
289
|
+
- `resolveRequestedWorkspaceBootstrapStatus(payload, workspaceSlug = "")`
|
|
289
290
|
- `resolveRouteState(placementRuntime, router)`
|
|
290
291
|
- `resolveSearchFromFullPath(fullPath = "")`
|
|
291
292
|
|
|
292
293
|
### `src/client/support/realtimeWorkspace.js`
|
|
293
294
|
Exports
|
|
294
|
-
- `matchesCurrentWorkspaceEvent(payload
|
|
295
|
+
- `matchesCurrentWorkspaceEvent(payload, workspaceSlug = "")`
|
|
295
296
|
- `createWorkspaceRealtimeMatcher(workspaceSlugRef)`
|
|
296
297
|
|
|
297
298
|
### `src/client/support/runtimeNormalization.js`
|
|
298
299
|
Exports
|
|
299
|
-
- `normalizeRecord(value)`
|
|
300
300
|
- `normalizeWorkspaceBootstrapStatusValue(status = "", allowedStatuses = null)`
|
|
301
301
|
- `resolveErrorStatusCode(error)`
|
|
302
302
|
|
|
@@ -308,7 +308,38 @@ Exports
|
|
|
308
308
|
Exports
|
|
309
309
|
- `WORKSPACES_WEB_SCOPE_SUPPORT_INJECTION_KEY`
|
|
310
310
|
- `createWorkspaceScopeSupport()`
|
|
311
|
-
- `readWorkspaceRouteScope(routeContext
|
|
311
|
+
- `readWorkspaceRouteScope(routeContext)`
|
|
312
|
+
|
|
313
|
+
### `src/client/types.js`
|
|
314
|
+
Exports
|
|
315
|
+
- `type WorkspacePlacementContext`
|
|
316
|
+
- `type WorkspacePlacementRuntime`
|
|
317
|
+
- `type ShellBootstrapRuntime`
|
|
318
|
+
- `type WorkspaceShell`
|
|
319
|
+
- `type WorkspaceRealtime`
|
|
320
|
+
- `type ShellGuardEvaluator`
|
|
321
|
+
- `type WorkspaceRouteScopeContext`
|
|
322
|
+
- `type WorkspaceBootstrapRuntime`
|
|
323
|
+
- `type WorkspaceScopeSupport`
|
|
324
|
+
- `type WorkspacesClient`
|
|
325
|
+
- `type WorkspaceRouteContext`
|
|
326
|
+
- `type WorkspaceSurfaceIds`
|
|
327
|
+
- `type WorkspaceMembersPage`
|
|
328
|
+
- `type WorkspaceMembersActions`
|
|
329
|
+
- `type WorkspacesLanding`
|
|
330
|
+
- `type AccountSettingsInvites`
|
|
331
|
+
- `type WorkspaceLinkResolver`
|
|
332
|
+
- `type PendingInvite`
|
|
333
|
+
- `type InviteAction`
|
|
334
|
+
- `type WorkspaceFeedback`
|
|
335
|
+
- `type MembersAdminForms`
|
|
336
|
+
- `type MembersAdminOptions`
|
|
337
|
+
- `type WorkspaceMember`
|
|
338
|
+
- `type WorkspaceMemberInvite`
|
|
339
|
+
- `type MembersAdminCollections`
|
|
340
|
+
- `type MembersAdminPermissions`
|
|
341
|
+
- `type MembersAdminStatus`
|
|
342
|
+
- `type MembersAdminActions`
|
|
312
343
|
|
|
313
344
|
### `src/shared/toolsOutletContracts.js`
|
|
314
345
|
Exports
|
|
@@ -324,6 +355,16 @@ Exports
|
|
|
324
355
|
Exports
|
|
325
356
|
- None
|
|
326
357
|
|
|
358
|
+
### `fixtures/workspaces-components/main.js`
|
|
359
|
+
Exports
|
|
360
|
+
- None
|
|
361
|
+
Local functions
|
|
362
|
+
- `pageFor(label)`
|
|
363
|
+
|
|
364
|
+
### `fixtures/workspaces-components/vite.config.mjs`
|
|
365
|
+
Exports
|
|
366
|
+
- None
|
|
367
|
+
|
|
327
368
|
### `fixtures/workspaces-landing/main.js`
|
|
328
369
|
Exports
|
|
329
370
|
- None
|
|
@@ -122,6 +122,23 @@ function useAttachments({ uploadAttachment = null } = {}) {
|
|
|
122
122
|
if (typeof uploadAttachment !== "function") return;
|
|
123
123
|
```
|
|
124
124
|
|
|
125
|
+
Each `typeof` probe is one of these, decided by reading its callers:
|
|
126
|
+
|
|
127
|
+
| The probe | What it is | What it becomes |
|
|
128
|
+
| --- | --- | --- |
|
|
129
|
+
| `typeof socket.on === "function"` on a value with a contract | a member every implementer has | the contract, typed once; the probe goes |
|
|
130
|
+
| `if (typeof onEvent !== "function") throw` | an "x is required" guard | a required option; the guard goes |
|
|
131
|
+
| `typeof matches === "function" && matches(context)` | an option real callers omit | a [named default](#absent-options), called plainly |
|
|
132
|
+
| `typeof deleteAttachment === "function"` | a contract member some real caller lacks | an [optional operation](#absent-options) |
|
|
133
|
+
| `typeof guard === "function"` on an option documented as `false`, a function or options | telling the shapes of one option apart | a check of the data, `isRecord(guard)`; the probe goes |
|
|
134
|
+
| a shape check on an injected value, to learn whether it is there | an availability test | [one comparison](#injected-accessors) with the named default |
|
|
135
|
+
| `typeof window !== "undefined"` | a host object | a [platform probe](#platform-probes) |
|
|
136
|
+
| `typeof config.debug === "boolean"` | a check of data, not a collaborator | stays |
|
|
137
|
+
|
|
138
|
+
A test that only pins a probe (`disconnect(null)` does nothing, `connect: null`
|
|
139
|
+
is refused) goes with the probe; a test that reaches production code through a
|
|
140
|
+
double keeps its assertions, and the double gains what the code now calls.
|
|
141
|
+
|
|
125
142
|
### Absent options
|
|
126
143
|
|
|
127
144
|
**What a real caller leaves out takes one of the server's two forms.** A
|
|
@@ -246,6 +263,51 @@ const support = inject("workspaceScope", null);
|
|
|
246
263
|
if (!support || typeof support.readRouteScope !== "function") return FALLBACK;
|
|
247
264
|
```
|
|
248
265
|
|
|
266
|
+
### Injected accessors
|
|
267
|
+
|
|
268
|
+
**A `use<Name>()` accessor takes no `required` option: the key's owner decides
|
|
269
|
+
once, and it resolves one way.** When no real application runs without the
|
|
270
|
+
provider, it is `inject(KEY)`. When one does, it is `inject(KEY, NO_X)`, and
|
|
271
|
+
`NO_X` has every member of the contract, each doing nothing, so callers call it
|
|
272
|
+
plainly.
|
|
273
|
+
|
|
274
|
+
- A caller that behaves differently when the value is absent compares once with
|
|
275
|
+
the named default, `socket !== NO_REALTIME_SOCKET`, and branches on that.
|
|
276
|
+
- A caller that cannot work without the value compares and refuses once, where
|
|
277
|
+
it receives it; a `required` option on the owner's accessor is not the way.
|
|
278
|
+
- The accessor keeps no shape check of what was provided: a provider supplies
|
|
279
|
+
the contract, and a test double completes it.
|
|
280
|
+
|
|
281
|
+
Why: a mode and a shape check give one key several outcomes, and each caller
|
|
282
|
+
has to know which it got. A default that lacks members moves the probes to the
|
|
283
|
+
callers (`socket.connect?.()`).
|
|
284
|
+
|
|
285
|
+
```js
|
|
286
|
+
// good: src/client/composables/useRealtimeEvent.js
|
|
287
|
+
const NO_REALTIME_SOCKET = Object.freeze({
|
|
288
|
+
connected: false,
|
|
289
|
+
connect() {},
|
|
290
|
+
on() {},
|
|
291
|
+
off() {}
|
|
292
|
+
});
|
|
293
|
+
/** @returns {import("../types.js").RealtimeSocket} */
|
|
294
|
+
function useRealtimeSocket() {
|
|
295
|
+
return inject(REALTIME_SOCKET_KEY, NO_REALTIME_SOCKET);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// good: a caller that needs one
|
|
299
|
+
const socket = useRealtimeSocket();
|
|
300
|
+
if (socket === NO_REALTIME_SOCKET) throw new Error("Conversations need the realtime socket.");
|
|
301
|
+
|
|
302
|
+
// bad
|
|
303
|
+
function useRealtimeSocket({ required = false } = {}) {
|
|
304
|
+
const socket = inject(REALTIME_SOCKET_KEY, null);
|
|
305
|
+
if (socket && typeof socket.on === "function") return socket;
|
|
306
|
+
if (required) throw new Error("No socket.");
|
|
307
|
+
return EMPTY_SOCKET;
|
|
308
|
+
}
|
|
309
|
+
```
|
|
310
|
+
|
|
249
311
|
## Components
|
|
250
312
|
|
|
251
313
|
### Collaborator props
|
|
@@ -456,7 +518,7 @@ client-only rules below. The server's action and error rules do not apply.
|
|
|
456
518
|
|
|
457
519
|
| Rule | Reports | Section |
|
|
458
520
|
| --- | --- | --- |
|
|
459
|
-
| `jskit/typed-inject` | `inject()` with a literal key, an untyped binding,
|
|
521
|
+
| `jskit/typed-inject` | `inject()` with a literal key, an untyped binding, a `null` / `{}` default, or in a function with a `required` option | [Injected values](#injected-values), [Injected accessors](#injected-accessors) |
|
|
460
522
|
| `jskit/collaborator-props` | a prop the component calls that is optional with no named default, or typed only `Object` | [Collaborator props](#collaborator-props) |
|
|
461
523
|
| `jskit/fixed-result-shape` | behaviour assigned to a `use*` / `create*` result after it is built, also one a wrapper's callback built | [Fixed result shape](#fixed-result-shape) |
|
|
462
524
|
| `jskit/no-frozen-vue-state` | `Object.freeze` over refs, computeds or reactive state | [Fixed result shape](#fixed-result-shape) |
|
|
@@ -35,6 +35,10 @@ rule's intent, and report the case.
|
|
|
35
35
|
- [Client providers](../client-features.md#client-providers)
|
|
36
36
|
- `inject("key")`, `inject(KEY, null)`, `inject(KEY, {})` (`jskit/typed-inject`)
|
|
37
37
|
- [Injected values](../client-features.md#injected-values)
|
|
38
|
+
- `useX({ required })`, an `EMPTY_*` fallback, a shape check of an injected value, `socket.connect?.()` on a default (`jskit/typed-inject`)
|
|
39
|
+
- [Injected accessors](../client-features.md#injected-accessors)
|
|
40
|
+
- which kind of `typeof` probe this is, a test that only pins a probe
|
|
41
|
+
- [Required options](../client-features.md#required-options)
|
|
38
42
|
- `type: Object, default: null` on a prop the component calls, `adapter: Object` (`jskit/collaborator-props`, `vue/require-default-prop`)
|
|
39
43
|
- [Collaborator props](../client-features.md#collaborator-props)
|
|
40
44
|
- an event emitted but not declared (`vue/require-explicit-emits`)
|