@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.
Files changed (230) hide show
  1. package/guide/agent/app-extras/assistant-conversation.md +88 -35
  2. package/guide/agent/app-extras/assistant.md +28 -28
  3. package/guide/agent/app-setup/authentication.md +36 -17
  4. package/guide/agent/app-setup/database-layer.md +116 -17
  5. package/guide/agent/app-setup/existing-application-migration.md +29 -25
  6. package/guide/agent/app-setup/multi-homing.md +94 -48
  7. package/guide/agent/app-setup/run-an-accounts-hub.md +6 -4
  8. package/guide/agent/framework/client-features.md +496 -0
  9. package/guide/agent/framework/crud-operations.md +5 -5
  10. package/guide/agent/framework/translation.md +4 -3
  11. package/guide/agent/framework/typed-features.md +1104 -0
  12. package/guide/agent/framework/ui-operations.md +2 -2
  13. package/guide/agent/index.md +6 -1
  14. package/package.json +1 -1
  15. package/patterns/feature-package/PATTERN.md +104 -10
  16. package/patterns/feature-package/example/booking-engine/package.json +9 -4
  17. package/patterns/feature-package/example/booking-engine/src/server/BookingEngineFeature.js +24 -0
  18. package/patterns/feature-package/example/booking-engine/src/server/bookingAvailability.js +10 -0
  19. package/patterns/feature-package/example/booking-engine/src/server/bookingEngine.js +29 -0
  20. package/patterns/feature-package/example/booking-engine/src/server/bookingEngineActions.js +26 -0
  21. package/patterns/feature-package/example/booking-engine/src/server/inputSchemas.js +1 -2
  22. package/patterns/feature-package/example/booking-engine/src/server/types.js +12 -0
  23. package/patterns/feature-package/example/variations/AvailabilityEngineFeature.js +19 -0
  24. package/patterns/feature-package/example/variations/InvoiceRollupFeature.js +23 -0
  25. package/patterns/feature-package/example/variations/availabilityEngineActions.js +26 -0
  26. package/patterns/feature-package/example/variations/customKnexRepository.js +32 -26
  27. package/patterns/feature-package/example/variations/invoiceRollupActions.js +26 -0
  28. package/patterns/feature-package/example/variations/orchestratorService.js +24 -19
  29. package/patterns/feature-package/example/variations/types.js +7 -0
  30. package/patterns/minimal-foundation/PATTERN.md +30 -1
  31. package/patterns/minimal-foundation/example/AGENTS.md +14 -0
  32. package/patterns/minimal-foundation/example/bin/develop.js +10 -5
  33. package/patterns/minimal-foundation/example/eslint.config.mjs +21 -2
  34. package/patterns/minimal-foundation/example/package.json +5 -4
  35. package/patterns/minimal-foundation/example/playwright.config.mjs +1 -1
  36. package/patterns/minimal-foundation/example/server/lib/envFile.js +19 -0
  37. package/patterns/minimal-foundation/example/server/lib/loggerOptions.js +15 -0
  38. package/patterns/minimal-foundation/example/server/lib/runtimeEnv.js +17 -17
  39. package/patterns/minimal-foundation/example/server.js +32 -29
  40. package/patterns/minimal-foundation/example/tests/server/smoke.test.js +2 -1
  41. package/patterns/shell-foundation/PATTERN.md +29 -0
  42. package/patterns/shell-foundation/example/AGENTS.md +14 -0
  43. package/patterns/shell-foundation/example/bin/develop.js +10 -5
  44. package/patterns/shell-foundation/example/eslint.config.mjs +21 -2
  45. package/patterns/shell-foundation/example/package.json +6 -5
  46. package/patterns/shell-foundation/example/packages/main/package.json +1 -1
  47. package/patterns/shell-foundation/example/packages/main/src/client/providers/MainClientProvider.js +1 -0
  48. package/patterns/shell-foundation/example/playwright.config.mjs +1 -1
  49. package/patterns/shell-foundation/example/server/lib/envFile.js +19 -0
  50. package/patterns/shell-foundation/example/server/lib/loggerOptions.js +15 -0
  51. package/patterns/shell-foundation/example/server/lib/runtimeEnv.js +17 -17
  52. package/patterns/shell-foundation/example/server.js +32 -29
  53. package/patterns/shell-foundation/example/tests/server/smoke.test.js +2 -1
  54. package/reference/autogen/KERNEL_MAP.md +14 -8
  55. package/reference/autogen/PATTERN_INDEX.md +37 -37
  56. package/reference/autogen/README.md +2 -0
  57. package/reference/autogen/packages/agent-docs.md +70 -26
  58. package/reference/autogen/packages/agent-runtime.md +129 -0
  59. package/reference/autogen/packages/agent.md +149 -0
  60. package/reference/autogen/packages/architecture-inspector.md +97 -44
  61. package/reference/autogen/packages/assistant-core.md +786 -292
  62. package/reference/autogen/packages/assistant-runtime.md +182 -57
  63. package/reference/autogen/packages/assistant-voice-sherpa.md +4 -0
  64. package/reference/autogen/packages/assistant-voice.md +54 -8
  65. package/reference/autogen/packages/auth-core.md +44 -13
  66. package/reference/autogen/packages/auth-provider-local-core.md +86 -34
  67. package/reference/autogen/packages/auth-provider-local-db-core.md +1 -2
  68. package/reference/autogen/packages/auth-provider-oidc-core.md +10 -4
  69. package/reference/autogen/packages/auth-provider-supabase-core.md +52 -66
  70. package/reference/autogen/packages/auth-web.md +19 -11
  71. package/reference/autogen/packages/connectors-catalog.md +71 -43
  72. package/reference/autogen/packages/connectors-core.md +42 -4
  73. package/reference/autogen/packages/console-core.md +27 -14
  74. package/reference/autogen/packages/crud-core.md +178 -170
  75. package/reference/autogen/packages/database-runtime-mysql.md +0 -2
  76. package/reference/autogen/packages/database-runtime-postgres.md +0 -2
  77. package/reference/autogen/packages/database-runtime.md +39 -10
  78. package/reference/autogen/packages/http-runtime.md +79 -57
  79. package/reference/autogen/packages/json-rest-api-core.md +11 -8
  80. package/reference/autogen/packages/kernel.md +144 -83
  81. package/reference/autogen/packages/oidc-issuer-core.md +49 -20
  82. package/reference/autogen/packages/payments-core.md +20 -3
  83. package/reference/autogen/packages/realtime.md +47 -22
  84. package/reference/autogen/packages/resource-core.md +1 -1
  85. package/reference/autogen/packages/resource-crud-core.md +64 -26
  86. package/reference/autogen/packages/rewarded-core.md +47 -36
  87. package/reference/autogen/packages/shell-web.md +7 -10
  88. package/reference/autogen/packages/storage-runtime.md +6 -2
  89. package/reference/autogen/packages/uploads-runtime.md +10 -2
  90. package/reference/autogen/packages/users-core.md +73 -71
  91. package/reference/autogen/packages/workspaces-core.md +121 -106
  92. package/reference/autogen/packages/workspaces-web.md +1 -2
  93. package/reference/autogen/tooling/config-eslint.md +302 -0
  94. package/reference/autogen/tooling/jskit-catalog.md +28 -18
  95. package/reference/autogen/tooling/jskit-release.md +35 -20
  96. package/reference/autogen/tooling/testUtils.md +3 -1
  97. package/skills/jskit/SKILL.md +9 -8
  98. package/skills/jskit/references/app-operations.md +1 -1
  99. package/skills/jskit/references/client-features.md +491 -0
  100. package/skills/jskit/references/crud-form-actions.md +1 -1
  101. package/skills/jskit/references/crud-operations.md +7 -7
  102. package/skills/jskit/references/existing-application-migration.md +31 -27
  103. package/skills/jskit/references/heuristics/INDEX.md +5 -1
  104. package/skills/jskit/references/heuristics/child-cruds.md +1 -1
  105. package/skills/jskit/references/heuristics/client-features.md +66 -0
  106. package/skills/jskit/references/heuristics/client-requests.md +1 -1
  107. package/skills/jskit/references/heuristics/crud-authoring.md +12 -2
  108. package/skills/jskit/references/heuristics/crud-links.md +1 -1
  109. package/skills/jskit/references/heuristics/crud-repository-mapping.md +3 -3
  110. package/skills/jskit/references/heuristics/filters.md +1 -1
  111. package/skills/jskit/references/heuristics/live-actions.md +1 -1
  112. package/skills/jskit/references/heuristics/page-redirects.md +1 -1
  113. package/skills/jskit/references/heuristics/page-scaffolding.md +1 -1
  114. package/skills/jskit/references/heuristics/placements.md +1 -1
  115. package/skills/jskit/references/heuristics/row-policies.md +1 -1
  116. package/skills/jskit/references/heuristics/server-search.md +1 -1
  117. package/skills/jskit/references/heuristics/surfaces.md +1 -1
  118. package/skills/jskit/references/heuristics/typed-features.md +100 -0
  119. package/skills/jskit/references/heuristics/ui-contract.md +1 -1
  120. package/skills/jskit/references/heuristics/ui-testing.md +4 -4
  121. package/skills/jskit/references/material-3.md +2 -2
  122. package/skills/jskit/references/multi-homing.md +96 -50
  123. package/skills/jskit/references/pattern-index.md +37 -37
  124. package/skills/jskit/references/patterns/app/minimal-foundation/PATTERN.md +30 -1
  125. package/skills/jskit/references/patterns/app/minimal-foundation/example/AGENTS.md +14 -0
  126. package/skills/jskit/references/patterns/app/minimal-foundation/example/bin/develop.js +10 -5
  127. package/skills/jskit/references/patterns/app/minimal-foundation/example/eslint.config.mjs +21 -2
  128. package/skills/jskit/references/patterns/app/minimal-foundation/example/package.json +5 -4
  129. package/skills/jskit/references/patterns/app/minimal-foundation/example/playwright.config.mjs +1 -1
  130. package/skills/jskit/references/patterns/app/minimal-foundation/example/server/lib/envFile.js +19 -0
  131. package/skills/jskit/references/patterns/app/minimal-foundation/example/server/lib/loggerOptions.js +15 -0
  132. package/skills/jskit/references/patterns/app/minimal-foundation/example/server/lib/runtimeEnv.js +17 -17
  133. package/skills/jskit/references/patterns/app/minimal-foundation/example/server.js +32 -29
  134. package/skills/jskit/references/patterns/app/minimal-foundation/example/tests/server/smoke.test.js +2 -1
  135. package/skills/jskit/references/patterns/app/shell-foundation/PATTERN.md +29 -0
  136. package/skills/jskit/references/patterns/app/shell-foundation/example/AGENTS.md +14 -0
  137. package/skills/jskit/references/patterns/app/shell-foundation/example/bin/develop.js +10 -5
  138. package/skills/jskit/references/patterns/app/shell-foundation/example/eslint.config.mjs +21 -2
  139. package/skills/jskit/references/patterns/app/shell-foundation/example/package.json +6 -5
  140. package/skills/jskit/references/patterns/app/shell-foundation/example/packages/main/package.json +1 -1
  141. package/skills/jskit/references/patterns/app/shell-foundation/example/packages/main/src/client/providers/MainClientProvider.js +1 -0
  142. package/skills/jskit/references/patterns/app/shell-foundation/example/playwright.config.mjs +1 -1
  143. package/skills/jskit/references/patterns/app/shell-foundation/example/server/lib/envFile.js +19 -0
  144. package/skills/jskit/references/patterns/app/shell-foundation/example/server/lib/loggerOptions.js +15 -0
  145. package/skills/jskit/references/patterns/app/shell-foundation/example/server/lib/runtimeEnv.js +17 -17
  146. package/skills/jskit/references/patterns/app/shell-foundation/example/server.js +32 -29
  147. package/skills/jskit/references/patterns/app/shell-foundation/example/tests/server/smoke.test.js +2 -1
  148. package/skills/jskit/references/patterns/assistant/assistant-surface/example/src/ApplicationAiFeature.js +4 -2
  149. package/skills/jskit/references/patterns/auth/accounts-hub/PATTERN.md +2 -1
  150. package/skills/jskit/references/patterns/auth/accounts-hub/example/package.json +2 -2
  151. package/skills/jskit/references/patterns/auth/accounts-hub/example/server/hubPaths.js +9 -3
  152. package/skills/jskit/references/patterns/auth/auth-surface/PATTERN.md +25 -12
  153. package/skills/jskit/references/patterns/auth/auth-surface/example/tools/preview-identity +7 -1
  154. package/skills/jskit/references/patterns/auth/oidc-sign-in/example/package.json +2 -2
  155. package/skills/jskit/references/patterns/auth/supabase-auth/example/package.json +1 -1
  156. package/skills/jskit/references/patterns/connectors/ai-connections/PATTERN.md +16 -1
  157. package/skills/jskit/references/patterns/connectors/ai-connections/example/ai-model.js +12 -3
  158. package/skills/jskit/references/patterns/connectors/ai-connections/example/perplexity-answer.js +15 -4
  159. package/skills/jskit/references/patterns/connectors/api-key-connection/PATTERN.md +9 -1
  160. package/skills/jskit/references/patterns/connectors/api-key-connection/example/connections.js +5 -2
  161. package/skills/jskit/references/patterns/connectors/aws-storage-queries/PATTERN.md +13 -3
  162. package/skills/jskit/references/patterns/connectors/aws-storage-queries/example/s3-transfer.js +14 -3
  163. package/skills/jskit/references/patterns/connectors/calendar-cli/PATTERN.md +8 -0
  164. package/skills/jskit/references/patterns/connectors/calendar-cli/example/knexfile.js +1 -1
  165. package/skills/jskit/references/patterns/connectors/calendar-cli/example/package.json +4 -4
  166. package/skills/jskit/references/patterns/connectors/calendar-cli/example/scripts/calendar.js +8 -4
  167. package/skills/jskit/references/patterns/connectors/event-delivery/PATTERN.md +1 -1
  168. package/skills/jskit/references/patterns/connectors/firebase-messaging/PATTERN.md +10 -0
  169. package/skills/jskit/references/patterns/connectors/firebase-messaging/example/server/notifications.js +8 -0
  170. package/skills/jskit/references/patterns/connectors/google-ads-search/PATTERN.md +18 -7
  171. package/skills/jskit/references/patterns/connectors/google-ads-search/example/ads-setup.js +13 -5
  172. package/skills/jskit/references/patterns/connectors/oauth-connection/PATTERN.md +1 -1
  173. package/skills/jskit/references/patterns/connectors/paddle-catalogue/PATTERN.md +11 -2
  174. package/skills/jskit/references/patterns/connectors/paddle-catalogue/example/create-products.js +5 -2
  175. package/skills/jskit/references/patterns/connectors/public-image/PATTERN.md +10 -1
  176. package/skills/jskit/references/patterns/connectors/public-image/example/logo-url.js +4 -1
  177. package/skills/jskit/references/patterns/connectors/redshift-queries/PATTERN.md +1 -1
  178. package/skills/jskit/references/patterns/connectors/source-scanning/PATTERN.md +13 -2
  179. package/skills/jskit/references/patterns/connectors/source-scanning/example/source-scanner.js +9 -0
  180. package/skills/jskit/references/patterns/crud/json-api-resource-package/PATTERN.md +102 -23
  181. package/skills/jskit/references/patterns/crud/json-api-resource-package/example/packages/books/package.json +3 -2
  182. package/skills/jskit/references/patterns/crud/json-api-resource-package/example/packages/books/src/server/types.js +5 -0
  183. package/skills/jskit/references/patterns/crud/resource-contract/PATTERN.md +54 -1
  184. package/skills/jskit/references/patterns/database/mysql-application/PATTERN.md +16 -5
  185. package/skills/jskit/references/patterns/database/mysql-application/example/knexfile.js +2 -2
  186. package/skills/jskit/references/patterns/database/mysql-application/example/package.json +1 -1
  187. package/skills/jskit/references/patterns/database/mysql-application/example/scripts/prepare-database.js +1 -1
  188. package/skills/jskit/references/patterns/database/postgres-application/PATTERN.md +16 -5
  189. package/skills/jskit/references/patterns/database/postgres-application/example/knexfile.js +2 -2
  190. package/skills/jskit/references/patterns/database/postgres-application/example/package.json +1 -1
  191. package/skills/jskit/references/patterns/database/postgres-application/example/scripts/prepare-database.js +1 -1
  192. package/skills/jskit/references/patterns/realtime/realtime-application/example/package.json +2 -2
  193. package/skills/jskit/references/patterns/rewards/google-rewarded/example/GoogleRewardedDeliveryProvider.js +1 -1
  194. package/skills/jskit/references/patterns/rewards/google-rewarded/example/googlePublisherTag.js +5 -11
  195. package/skills/jskit/references/patterns/server/feature-package/PATTERN.md +104 -10
  196. package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/package.json +9 -4
  197. package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/BookingEngineFeature.js +24 -0
  198. package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/bookingAvailability.js +10 -0
  199. package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/bookingEngine.js +29 -0
  200. package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/bookingEngineActions.js +26 -0
  201. package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/inputSchemas.js +1 -2
  202. package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/types.js +12 -0
  203. package/skills/jskit/references/patterns/server/feature-package/example/variations/AvailabilityEngineFeature.js +19 -0
  204. package/skills/jskit/references/patterns/server/feature-package/example/variations/InvoiceRollupFeature.js +23 -0
  205. package/skills/jskit/references/patterns/server/feature-package/example/variations/availabilityEngineActions.js +26 -0
  206. package/skills/jskit/references/patterns/server/feature-package/example/variations/customKnexRepository.js +32 -26
  207. package/skills/jskit/references/patterns/server/feature-package/example/variations/invoiceRollupActions.js +26 -0
  208. package/skills/jskit/references/patterns/server/feature-package/example/variations/orchestratorService.js +24 -19
  209. package/skills/jskit/references/patterns/server/feature-package/example/variations/types.js +7 -0
  210. package/skills/jskit/references/patterns/users/user-administration-server/PATTERN.md +16 -1
  211. package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users/package.json +3 -2
  212. package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users/src/server/types.js +5 -0
  213. package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users-workspace/package.json +4 -3
  214. package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users-workspace/src/server/UsersWorkspaceFeature.js +2 -9
  215. package/skills/jskit/references/patterns/users/user-administration-server/example/packages/users-workspace/src/server/types.js +5 -0
  216. package/skills/jskit/references/patterns/workspaces/workspace-server/PATTERN.md +42 -17
  217. package/skills/jskit/references/patterns/workspaces/workspace-server/example/packages/main/src/server/WorkspaceInvitationsFeature.js +27 -0
  218. package/skills/jskit/references/patterns/workspaces/workspace-server/example/packages/main/src/server/email/workspaceInviteEmail.js +11 -10
  219. package/skills/jskit/references/patterns/workspaces/workspace-server/example/packages/main/src/server/email/workspaceInviteMailer.js +27 -0
  220. package/skills/jskit/references/translation.md +5 -4
  221. package/skills/jskit/references/typed-features.md +1099 -0
  222. package/skills/jskit/references/ui-operations.md +3 -3
  223. package/patterns/feature-package/example/booking-engine/src/server/BookingEngineProvider.js +0 -33
  224. package/patterns/feature-package/example/booking-engine/src/server/actions.js +0 -24
  225. package/patterns/feature-package/example/variations/AvailabilityEngineProvider.js +0 -31
  226. package/patterns/feature-package/example/variations/InvoiceRollupProvider.js +0 -36
  227. package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/BookingEngineProvider.js +0 -33
  228. package/skills/jskit/references/patterns/server/feature-package/example/booking-engine/src/server/actions.js +0 -24
  229. package/skills/jskit/references/patterns/server/feature-package/example/variations/AvailabilityEngineProvider.js +0 -31
  230. package/skills/jskit/references/patterns/server/feature-package/example/variations/InvoiceRollupProvider.js +0 -36
@@ -18,7 +18,7 @@ The example wires that library to application-owned authority and snapshot looku
18
18
  ## Do not use when
19
19
 
20
20
  This is not an HTTP application-data connector, user login, a managed gateway,
21
- or an implementation of Vibe64's coding agents. It does not generate an app.
21
+ or an implementation of a hosted editor's coding agents. It does not generate an app.
22
22
  Auth0 and native Windows execution are not implemented in the current runner.
23
23
 
24
24
  ## Product decisions
@@ -39,7 +39,15 @@ and whether a blocking verdict prevents a later operation.
39
39
  - Missing/invalid reports, cancellation and failed scans never become clean scans.
40
40
  - Provider credentials are isolated from coding-agent sessions and credentials.
41
41
  - The host supplies its own authorized provider credentials; editor edition does
42
- not select a shared Vibe64 provider account.
42
+ not select a shared hosted provider account.
43
+ - Each collaborator the composition receives (`authorize`, `resolveReference`
44
+ and `resolveScanTarget`) is a required parameter typed in a JSDoc `@param` and
45
+ called directly, without a `typeof` probe, a "requires x" guard or a no-op
46
+ default. `authorize` and `resolveReference` are typed with `ConnectorAuthorize`
47
+ and `ResolveReference` from `@jskit-ai/connectors-core/server/types`, and
48
+ `resolveScanTarget` with `WizScanTargetResolver` from
49
+ `@jskit-ai/connectors-catalog/server/types`. A server feature that uses it follows
50
+ [typed features](https://github.com/mobily-enterprises/jskit-ai/blob/main/packages/agent-docs/site/guide/framework/typed-features.md).
43
51
 
44
52
  ## Framework APIs
45
53
 
@@ -81,3 +89,6 @@ and findings require separately authorised provider acceptance.
81
89
  Do not infer workspace grants from a shared slot, return raw provider stderr,
82
90
  replay scans automatically, pass arbitrary CLI flags, use a mutable working tree
83
91
  as if it were a fixed revision, or substitute a generic API reader for source scans.
92
+
93
+ Do not probe a collaborator, default one to `null`, `{}` or a no-op, fill a slot
94
+ with a setter after construction, or keep a module-level registry.
@@ -3,6 +3,15 @@ import { parseIntegrationConfiguration } from "@jskit-ai/connectors-core/shared/
3
3
  import { wizDefinition } from "@jskit-ai/connectors-catalog/shared";
4
4
  import { createWizScanner } from "@jskit-ai/connectors-catalog/server/wiz";
5
5
 
6
+ /**
7
+ * @param {object} dependencies
8
+ * @param {string} [dependencies.configFile]
9
+ * @param {string} dependencies.installedWizCliPath
10
+ * @param {import("@jskit-ai/connectors-core/server/types").ConnectorAuthorize} dependencies.authorize The application's access policy.
11
+ * @param {import("@jskit-ai/connectors-core/server/types").ResolveReference} dependencies.resolveReference
12
+ * @param {import("@jskit-ai/connectors-catalog/server/types").WizScanTargetResolver} dependencies.resolveScanTarget
13
+ * @param {Record<string, string>} [dependencies.environment]
14
+ */
6
15
  export async function projectSourceScanner({ configFile = "integrations.json", installedWizCliPath,
7
16
  authorize, resolveReference, resolveScanTarget, environment }) {
8
17
  const configuration = parseIntegrationConfiguration(await readFile(configFile, "utf8"), {
@@ -33,18 +33,32 @@ from a generator questionnaire or treat a live table as the sole contract.
33
33
  - Migration and resource storage metadata describe the same table.
34
34
  - `apiAccess`, surface access, and `autofilter` agree.
35
35
  - Public routes use public ownership only.
36
- - Workspace routes receive explicit scope validators and route-to-action input.
36
+ - Workspace routes receive explicit scope validators and route-to-action input:
37
+ workspaces-core's `WORKSPACE_CRUD_SCOPE`, never a copied scope literal.
37
38
  - Application source contains one module declaration, not copied generic CRUD
38
39
  repository, service, action, route, and provider files.
39
40
  - Current migration/resource/source state is authoritative; there is no receipt,
40
41
  provenance marker, generator identity, or field-patching lane.
42
+ - The package exports the type of the capability it provides:
43
+ `src/server/types.js` declares `AppBooks` (for `app.books`) as crud-core's
44
+ `CrudResourceApi`, exported as `./server/types`. A feature that requires
45
+ `app.books` names that type in a JSDoc `@param`; code given only its service
46
+ or repository names crud-core's `CrudService` or `CrudRepository`.
47
+ - Code the declaration adds follows [typed features](https://github.com/mobily-enterprises/jskit-ai/blob/main/packages/agent-docs/site/guide/framework/typed-features.md):
48
+ `decorateService`, `decorateRepository`, `operationLifecycle` hooks and named
49
+ `actions` call the collaborators they receive directly, with no `typeof`
50
+ probe, optional call, absent default, slot setter or module-level registry.
51
+ Each action's `execute` is one call to one service method with the
52
+ validated input, and its argument is typed as crud-core's
53
+ `CrudCustomActionInvocation`. Keep one copy of each helper per package, files
54
+ under 750 lines and functions under 600.
41
55
 
42
56
  ## Framework APIs
43
57
 
44
58
  Use `defineCrudResource()` from `@jskit-ai/resource-crud-core` and
45
59
  `defineCrudJsonApiFeature()` from `@jskit-ai/crud-core`. The latter composes the
46
- JSON REST resource, repository, service events, standard CRUD actions, route
47
- contracts, access policy, and HTTP routes.
60
+ JSON REST resource, repository, service, standard CRUD actions with their
61
+ record-changed events, route contracts, access policy, and HTTP routes.
48
62
 
49
63
  ## Example files
50
64
 
@@ -55,6 +69,7 @@ Paths below are relative to this pattern directory:
55
69
  example/migrations/20260815000000_books.cjs
56
70
  example/packages/books/package.json
57
71
  example/packages/books/src/server/BooksFeature.js
72
+ example/packages/books/src/server/types.js
58
73
  example/packages/books/src/shared/bookResource.js
59
74
  example/packages/books/src/shared/index.js
60
75
  ```
@@ -67,6 +82,8 @@ guide.
67
82
 
68
83
  `BooksFeature.js` is deliberately tiny: it binds the readable resource contract
69
84
  to the framework module and exports the resulting provider.
85
+ `types.js` declares the type of the `app.books` capability, for features that
86
+ require it.
70
87
 
71
88
  ## List search is part of the initial composition
72
89
 
@@ -89,8 +106,15 @@ an unfiltered collection can satisfy a matching-row-only assertion.
89
106
 
90
107
  Change the package name, resource fields, table, surface, ownership filter,
91
108
  relative route, messages, and migration. Supply explicit permissions when the
92
- surface uses named policy. For workspace ownership, add the workspace route and
93
- action validators through the module's `scope` option. The feature exposes the
109
+ surface uses named policy. For workspace ownership, pass `scope:
110
+ WORKSPACE_CRUD_SCOPE` (`@jskit-ai/workspaces-core/server/support/workspaceCrud`):
111
+ the `/w/:workspaceSlug` route base, the workspace route and action validators
112
+ and the slug input. A repository method of such a feature reads the workspace
113
+ id with `resolveWorkspaceScopeValue(options.context)`
114
+ (`@jskit-ai/json-rest-api-core/server/jsonRestApiHost`), and a
115
+ hand-written workspace route's path is
116
+ `resolveWorkspaceRoutePath("relative-path")`
117
+ (`@jskit-ai/workspaces-core/server/support/workspaceRoutePaths`). The feature exposes the
94
118
  operations declared by the resource. Use `operations` only to narrow that
95
119
  surface further; do not register unused mutation actions and routes. Use
96
120
  `routes: false` only for an internal
@@ -108,7 +132,13 @@ capabilities in `requires` and provide `decorateService({ service, repository,
108
132
  resource, ...dependencies })`. Retain the standard methods, override only the
109
133
  methods whose CRUD behavior changes, and add resource-related domain methods
110
134
  such as `confirmBooking()` or `sendReminder()` directly to that service. Those
111
- additional methods remain available through the resource capability. When the
135
+ additional methods remain available through the resource capability. An
136
+ overridden `createDocument()` returns the created record, with its id, as a
137
+ tagged JSON:API result: a document result (`returnJsonApiDocument`), as the
138
+ standard one does, or a data result (`returnJsonApiData(record)`). The create
139
+ action's created and `record.changed` events read the record's id from it, and
140
+ a create whose service returns an untagged document or record, or a result
141
+ without the record's id, fails in every channel. When the
112
142
  product needs only a few additional queries or locking operations, provide
113
143
  `decorateRepository({ repository, database, http, jsonRestApi, resource,
114
144
  ...dependencies })`; return the standard methods plus only those unique
@@ -118,14 +148,28 @@ Use `operationLifecycle` for behavior surrounding a standard operation. Its
118
148
  per-operation `before`, `execute`, and `after` phases share one repository
119
149
  transaction for create, update, and delete. An `execute` hook receives
120
150
  `standard(nextInput)` so it can retain the framework write while adjusting its
121
- input or coordinating other repository work. `afterCommit` runs only after the
122
- mutation transaction succeeds. Put durable external delivery behind an outbox
123
- written inside the transaction; do not make an email or webhook the arbiter of
124
- whether an already-committed request appears successful.
151
+ input or coordinating other repository work, and returns what `standard()`
152
+ returns: the operation's tagged JSON:API result (null for delete). A create's
153
+ `execute` returns the created record with its id, as the document result
154
+ `standard()` returns or as `returnJsonApiData(record)`, because the create's
155
+ events read its id; a create that returns anything else fails inside its
156
+ transaction. `after` and `afterCommit` receive that `result`, so a record id is
157
+ `result.value.data.id` for a document result. `afterCommit` runs only after the
158
+ mutation transaction succeeds. A hook's argument is `CrudLifecycleContext` from
159
+ `@jskit-ai/crud-core/server/types`; type a lifecycle declared apart from its
160
+ feature with `CrudOperationLifecycle`, whose type arguments are the decorated
161
+ service and repository its hooks call. Put durable external delivery behind an
162
+ outbox written inside the transaction; do not make an email or webhook the
163
+ arbiter of whether an already-committed request appears successful.
125
164
 
126
165
  Declare resource-related non-CRUD commands in `actions`. Each named action has
127
166
  a normal JSKIT input, permission, audit, events, and `execute({ input, context,
128
- service, repository, ...dependencies })` contract. Its optional `route`
167
+ service, repository, ...dependencies })` contract. Type that argument with
168
+ `CrudCustomActionInvocation` from `@jskit-ai/crud-core/server/types`. Its first
169
+ type argument is the service the action calls, when `decorateService` adds the
170
+ method; its second holds the types of required capabilities the action uses,
171
+ by local name; its third is the repository the action calls, when
172
+ `decorateRepository` adds the method. Its optional `route`
129
173
  declares an HTTP method, path below the resource base, explicit route contract,
130
174
  status code, and optional request-to-action input mapper. This is the normal
131
175
  home for `confirm`, `publish`, `cancel`, `reorder`, or `sendReminder`. Move to a
@@ -139,25 +183,58 @@ Use `operationInputs.create` or `operationInputs.update` when a standard CRUD
139
183
  operation intentionally accepts a small virtual product field that is handled
140
184
  by the service decorator rather than stored on the resource row.
141
185
 
186
+ A decorator lives in a module of its own and returns its result frozen, with
187
+ each added method a named function. Spreading belongs here only, over the CRUD
188
+ service or repository, whose members are the contract's. `types.js` names the
189
+ decorated types once:
190
+
191
+ ```js
192
+ // bookingsService.js
193
+ import { AppError } from "@jskit-ai/kernel/server/runtime/errors";
194
+
195
+ /**
196
+ * The bookings service: the CRUD service plus booking confirmation and the
197
+ * checks and history its updates need.
198
+ * @param {object} dependencies
199
+ * @param {import("@jskit-ai/crud-core/server/types").CrudService} dependencies.service
200
+ * @param {import("./types.js").BookingsRepository} dependencies.repository
201
+ */
202
+ function decorateBookingsService({ service, repository }) {
203
+ async function confirmBooking(recordId, options) {
204
+ return repository.confirmBooking(recordId, options);
205
+ }
206
+
207
+ async function assertUpdateAllowed(recordId, options) {
208
+ if (await repository.isBookingLocked(recordId, options)) {
209
+ throw new AppError(409, "This booking is locked.", { code: "bookings.locked" });
210
+ }
211
+ }
212
+
213
+ async function recordUpdateCompleted(recordId, options) {
214
+ return repository.addBookingHistoryEntry(recordId, "updated", options);
215
+ }
216
+
217
+ return Object.freeze({ ...service, confirmBooking, assertUpdateAllowed, recordUpdateCompleted });
218
+ }
219
+
220
+ // types.js
221
+ /** @typedef {ReturnType<typeof import("./bookingsRepository.js").decorateBookingsRepository>} BookingsRepository */
222
+ /** @typedef {ReturnType<typeof import("./bookingsService.js").decorateBookingsService>} BookingsService */
223
+ ```
224
+
142
225
  ```js
143
226
  const BookingsFeature = defineCrudJsonApiFeature({
144
227
  resource: bookingResource,
145
228
  surface: "app",
146
- decorateService({ service, repository }) {
147
- return {
148
- ...service,
149
- async confirmBooking(recordId, options) {
150
- return repository.confirmBooking(recordId, options);
151
- }
152
- };
153
- },
229
+ decorateRepository: decorateBookingsRepository,
230
+ decorateService: decorateBookingsService,
154
231
  operationLifecycle: {
155
232
  update: {
156
233
  async before({ input, service, trx, context }) {
157
234
  await service.assertUpdateAllowed(input.recordId, { trx, context });
158
235
  },
159
236
  async afterCommit({ result, service, context }) {
160
- await service.recordUpdateCompleted(result.data.id, { context });
237
+ await service.recordUpdateCompleted(result.value.data.id, { context });
161
238
  }
162
239
  }
163
240
  },
@@ -165,9 +242,8 @@ const BookingsFeature = defineCrudJsonApiFeature({
165
242
  confirm: {
166
243
  input: confirmBookingInput,
167
244
  permission: { require: "all", permissions: ["bookings.confirm"] },
168
- execute({ input, context, service }) {
169
- return service.confirmBooking(input.recordId, { context });
170
- },
245
+ /** @param {import("@jskit-ai/crud-core/server/types").CrudCustomActionInvocation<import("./types.js").BookingsService>} action */
246
+ execute: ({ input, context, service }) => service.confirmBooking(input.recordId, { context }),
171
247
  route: {
172
248
  method: "POST",
173
249
  path: "/:recordId/confirm",
@@ -203,3 +279,6 @@ const BookingsFeature = defineCrudJsonApiFeature({
203
279
  - public access combined with user or workspace ownership
204
280
  - implicit workspace route parameters or permissions
205
281
  - receipt, replay, provenance, ownership-marker, or scaffold-shape files
282
+ - probing a collaborator, defaulting one to `null`, `{}` or a no-op, setters
283
+ that fill a slot after construction, and module-level registries in
284
+ decorators, lifecycle hooks or actions
@@ -5,11 +5,12 @@
5
5
  "type": "module",
6
6
  "exports": {
7
7
  "./server/BooksFeature": "./src/server/BooksFeature.js",
8
+ "./server/types": "./src/server/types.js",
8
9
  "./shared": "./src/shared/index.js"
9
10
  },
10
11
  "dependencies": {
11
- "@jskit-ai/crud-core": "0.2.3",
12
- "@jskit-ai/resource-crud-core": "0.1.194"
12
+ "@jskit-ai/crud-core": "0.2.4",
13
+ "@jskit-ai/resource-crud-core": "0.1.195"
13
14
  },
14
15
  "jskit": {
15
16
  "kind": "runtime",
@@ -0,0 +1,5 @@
1
+ // The type of the `app.books` capability, for features that require it.
2
+
3
+ /** @typedef {import("@jskit-ai/crud-core/server/types").CrudResourceApi} AppBooks */
4
+
5
+ export {};
@@ -44,7 +44,9 @@ not from a JSKIT questionnaire.
44
44
  - User ownership is represented by a non-null `user_id` column.
45
45
  - The resource's hidden `userId` field maps to that ownership column.
46
46
  - `autofilter: "user"` is used only for genuine current-user ownership.
47
- - Output, create, and patch participation is explicit on each product field.
47
+ - Each product field's output, create, and patch participation is its
48
+ `operations` block, or the default `defineCrudResource()` gives a field
49
+ without one (see Field operations and lookups below).
48
50
  - Temporal database values use the declared storage serializer.
49
51
  - The source-controlled migration and resource contract agree.
50
52
  - Server policy tests prove that one user cannot read or mutate another user's
@@ -60,6 +62,57 @@ Higher layers should consume this resource through JSKIT's CRUD service,
60
62
  repository, route, and UI APIs. They should not rebuild field validators or
61
63
  serialize requests independently.
62
64
 
65
+ ## Field operations and lookups
66
+
67
+ A field's `operations` name the operations it takes part in: `output` (the
68
+ record in every response), and `create` and `patch` (the request bodies; an
69
+ enabled `replace` uses the `create` fields unless a field names `replace`). A
70
+ field that leaves `operations` out takes the default:
71
+
72
+ | Field | Default `operations` |
73
+ | --- | --- |
74
+ | `primary: true` | `{}`: no operation; every record output already carries its `id` |
75
+ | `hidden: true` | `{}`: no operation |
76
+ | `readOnly: true` | `{ output: { required: true } }` |
77
+ | any other field | `{ output: { required: true }, create: { required: <the field's required> }, patch: { required: false } }` |
78
+
79
+ So a `required: true` field is required on create, and any other field is
80
+ optional there. An `operations` block you write always wins, for example
81
+ `operations: { output: {}, create: {}, patch: {} }` for a field that is
82
+ optional everywhere. Write the block only where it differs from the default:
83
+
84
+ ```js
85
+ schema: {
86
+ userId: { type: "id", required: true, hidden: true },
87
+ title: { type: "string", maxLength: 255, required: true, search: true },
88
+ notes: { type: "string", maxLength: 65535, nullable: true, search: true },
89
+ createdAt: { type: "dateTime", default: "now()", readOnly: true, storage: { writeSerializer: "datetime-utc" } }
90
+ }
91
+ ```
92
+
93
+ A field that looks up a record of another resource can name that resource's
94
+ namespace with `lookup`:
95
+
96
+ ```js
97
+ shelfId: { type: "id", nullable: true, search: true, lookup: "shelves" }
98
+ ```
99
+
100
+ `defineCrudResource()` expands it, where `lookup` stood, to:
101
+
102
+ ```js
103
+ relation: { kind: "lookup", namespace: "shelves", valueKey: "id" },
104
+ belongsTo: "shelves", // the namespace's JSON REST resource, camel-cased
105
+ as: "shelf", // the field key without its Id suffix
106
+ ui: { formControl: "autocomplete" }
107
+ ```
108
+
109
+ Keys you write beside `lookup` win: `belongsTo` and `as` replace the
110
+ filled-in values, and `relation` and `ui` are merged over them, so
111
+ `relation: { labelKey: "name" }` adds a label key and
112
+ `ui: { formControl: "select" }` picks a select. A field whose key has no `Id`
113
+ suffix must write `as`. The built resource equals one that writes the expanded
114
+ keys out.
115
+
63
116
  ## Example files
64
117
 
65
118
  - `example/bookResource.js` is a complete resource contract for personal book
@@ -38,7 +38,10 @@ decisions, not framework questions.
38
38
  ## Framework APIs
39
39
 
40
40
  Use `createKnexMigrationConfigFromApp()` from
41
- `@jskit-ai/database-runtime/server/knexMigrationConfig`. The running JSKIT
41
+ `@jskit-ai/database-runtime/server/knexMigrationConfig`, and
42
+ `prepareDatabaseFromApp()` from `@jskit-ai/database-runtime/server/databaseSetup`.
43
+ Both take the dialect and the application's environment
44
+ (`environment: process.env`), which they never read on their own. The running JSKIT
42
45
  application automatically selects the sole installed database driver, while
43
46
  Knex discovers package-owned migrations from the installed dependency graph.
44
47
 
@@ -50,6 +53,14 @@ Knex discovers package-owned migrations from the installed dependency graph.
50
53
  entrypoint for managed sessions and deployments. `example/.env.example` names
51
54
  the connection values and separate test databases without a secret.
52
55
 
56
+ `example/.github/workflows/verify.yml` is a normal app-owned CI workflow with
57
+ exactly one database service: `mariadb` (`mariadb:11.4`, `MARIADB_*`
58
+ variables, port `3306`, a `healthcheck.sh` health check). Copy it whole from
59
+ this pattern and adapt it as source rather than generating it from package
60
+ metadata. Do not combine it with the PostgreSQL pattern's workflow: a MySQL
61
+ application's workflow has no `postgres` service, `POSTGRES_*` variables, port
62
+ `5432`, or `pg_isready` option.
63
+
53
64
  `example/tests/browser/database.js` is the application-owned browser preparation
54
65
  helper. It requires the exact `BROWSER_TEST_DB_NAME`, rejects the ordinary and
55
66
  disposable `TEST_DB_NAME` databases,
@@ -93,10 +104,9 @@ it as `seed` to `prepareDatabaseFromApp()`.
93
104
  foreign-key checks remain enabled, and the normal database is unchanged.
94
105
  Also prove that a new pending migration is applied. Keep this as a regression
95
106
  test when adapting the example; reject a harness that recreates the schema.
96
-
97
- `example/.github/workflows/verify.yml` is a normal app-owned CI workflow with
98
- an explicit MariaDB service. Adapt it as source rather than generating it from
99
- package metadata.
107
+ - Confirm `.github/workflows/verify.yml` parses as YAML and declares only the
108
+ `mariadb` service. GitHub reports an unparseable workflow only as a failed
109
+ run with "no jobs were run".
100
110
 
101
111
  ## Avoid
102
112
 
@@ -104,4 +114,5 @@ package metadata.
104
114
  - generated `.env` secrets
105
115
  - depending on a live schema as the source contract
106
116
  - a second driver installed “just in case”
117
+ - any file, service, port, or variable copied from the PostgreSQL pattern
107
118
  - migration receipts, provenance, replay logs, or generator ownership
@@ -1,11 +1,11 @@
1
1
  import { createKnexMigrationConfigFromApp } from "@jskit-ai/database-runtime/server/knexMigrationConfig";
2
2
 
3
3
  try {
4
- process.loadEnvFile?.(".env");
4
+ process.loadEnvFile(".env");
5
5
  } catch (error) {
6
6
  if (error?.code !== "ENOENT") {
7
7
  throw error;
8
8
  }
9
9
  }
10
10
 
11
- export default await createKnexMigrationConfigFromApp({ client: "mysql2" });
11
+ export default await createKnexMigrationConfigFromApp({ client: "mysql2", environment: process.env });
@@ -8,6 +8,6 @@
8
8
  "db:migrate:status": "knex --knexfile ./knexfile.js migrate:list"
9
9
  },
10
10
  "dependencies": {
11
- "@jskit-ai/database-runtime-mysql": "0.1.250"
11
+ "@jskit-ai/database-runtime-mysql": "0.1.251"
12
12
  }
13
13
  }
@@ -1,3 +1,3 @@
1
1
  import { prepareDatabaseFromApp } from "@jskit-ai/database-runtime/server/databaseSetup";
2
2
 
3
- await prepareDatabaseFromApp({ client: "mysql2" });
3
+ await prepareDatabaseFromApp({ client: "mysql2", environment: process.env });
@@ -38,7 +38,10 @@ decisions, not framework questions.
38
38
  ## Framework APIs
39
39
 
40
40
  Use `createKnexMigrationConfigFromApp()` from
41
- `@jskit-ai/database-runtime/server/knexMigrationConfig`. The running JSKIT
41
+ `@jskit-ai/database-runtime/server/knexMigrationConfig`, and
42
+ `prepareDatabaseFromApp()` from `@jskit-ai/database-runtime/server/databaseSetup`.
43
+ Both take the dialect and the application's environment
44
+ (`environment: process.env`), which they never read on their own. The running JSKIT
42
45
  application automatically selects the sole installed database driver, while
43
46
  Knex discovers package-owned migrations from the installed dependency graph.
44
47
 
@@ -50,6 +53,14 @@ dialect. `example/scripts/prepare-database.js` is the portable
50
53
  migrate-then-seed entrypoint for managed sessions and deployments.
51
54
  `example/.env.example` names the five connection values without a secret.
52
55
 
56
+ `example/.github/workflows/verify.yml` is a normal app-owned CI workflow with
57
+ exactly one database service: `postgres` (`postgres:17`, `POSTGRES_*`
58
+ variables, port `5432`, a `pg_isready` health check). Copy it whole from this
59
+ pattern and adapt it as source rather than generating it from package metadata.
60
+ Do not combine it with the MySQL pattern's workflow: a PostgreSQL application's
61
+ workflow has no `mariadb` service, `MARIADB_*` variables, port `3306`, or
62
+ `healthcheck.sh` option.
63
+
53
64
  ## Variation points
54
65
 
55
66
  Change scripts, migration location, connection values, and secret injection to
@@ -66,10 +77,9 @@ it as `seed` to `prepareDatabaseFromApp()`.
66
77
  - Run `npm run db:migrate:status` and the application verification command.
67
78
  - Exercise one transaction and one negative connection case.
68
79
  - When a seed exists, run `db:prepare` twice and require the second run to be safe.
69
-
70
- `example/.github/workflows/verify.yml` is a normal app-owned CI workflow with
71
- an explicit PostgreSQL service. Adapt it as source rather than generating it
72
- from package metadata.
80
+ - Confirm `.github/workflows/verify.yml` parses as YAML and declares only the
81
+ `postgres` service. GitHub reports an unparseable workflow only as a failed
82
+ run with "no jobs were run".
73
83
 
74
84
  ## Avoid
75
85
 
@@ -77,4 +87,5 @@ from package metadata.
77
87
  - generated `.env` secrets
78
88
  - depending on a live schema as the source contract
79
89
  - a second driver installed “just in case”
90
+ - any file, service, port, or variable copied from the MySQL pattern
80
91
  - migration receipts, provenance, replay logs, or generator ownership
@@ -1,11 +1,11 @@
1
1
  import { createKnexMigrationConfigFromApp } from "@jskit-ai/database-runtime/server/knexMigrationConfig";
2
2
 
3
3
  try {
4
- process.loadEnvFile?.(".env");
4
+ process.loadEnvFile(".env");
5
5
  } catch (error) {
6
6
  if (error?.code !== "ENOENT") {
7
7
  throw error;
8
8
  }
9
9
  }
10
10
 
11
- export default await createKnexMigrationConfigFromApp({ client: "pg" });
11
+ export default await createKnexMigrationConfigFromApp({ client: "pg", environment: process.env });
@@ -8,6 +8,6 @@
8
8
  "db:migrate:status": "knex --knexfile ./knexfile.js migrate:list"
9
9
  },
10
10
  "dependencies": {
11
- "@jskit-ai/database-runtime-postgres": "0.1.249"
11
+ "@jskit-ai/database-runtime-postgres": "0.1.250"
12
12
  }
13
13
  }
@@ -1,3 +1,3 @@
1
1
  import { prepareDatabaseFromApp } from "@jskit-ai/database-runtime/server/databaseSetup";
2
2
 
3
- await prepareDatabaseFromApp({ client: "pg" });
3
+ await prepareDatabaseFromApp({ client: "pg", environment: process.env });
@@ -2,7 +2,7 @@
2
2
  "private": true,
3
3
  "type": "module",
4
4
  "dependencies": {
5
- "@jskit-ai/realtime": "0.2.6",
6
- "@jskit-ai/shell-web": "0.2.3"
5
+ "@jskit-ai/realtime": "0.2.7",
6
+ "@jskit-ai/shell-web": "0.2.4"
7
7
  }
8
8
  }
@@ -5,7 +5,7 @@ const GoogleRewardedDeliveryProvider = defineProvider({
5
5
  id: "app.rewarded.google",
6
6
  provides: { delivery: "client.rewarded-delivery" },
7
7
  setup() {
8
- return { delivery: { launchReward: launchGoogleRewardedAd } };
8
+ return { delivery: Object.freeze({ launchReward: launchGoogleRewardedAd }) };
9
9
  }
10
10
  });
11
11
 
@@ -71,14 +71,10 @@ function launchGoogleRewardedAd({
71
71
  let settled = false;
72
72
 
73
73
  const cleanup = () => {
74
- if (typeof pubads.removeEventListener === "function") {
75
- pubads.removeEventListener("rewardedSlotReady", handleReady);
76
- pubads.removeEventListener("rewardedSlotGranted", handleGranted);
77
- pubads.removeEventListener("rewardedSlotClosed", handleClosed);
78
- }
79
- if (typeof googletag.destroySlots === "function") {
80
- googletag.destroySlots([slot]);
81
- }
74
+ pubads.removeEventListener("rewardedSlotReady", handleReady);
75
+ pubads.removeEventListener("rewardedSlotGranted", handleGranted);
76
+ pubads.removeEventListener("rewardedSlotClosed", handleClosed);
77
+ googletag.destroySlots([slot]);
82
78
  };
83
79
 
84
80
  const handleReady = async (event) => {
@@ -87,9 +83,7 @@ function launchGoogleRewardedAd({
87
83
  }
88
84
  readySeen = true;
89
85
  await Promise.resolve(onReady?.());
90
- if (typeof event.makeRewardedVisible === "function") {
91
- event.makeRewardedVisible();
92
- }
86
+ event.makeRewardedVisible();
93
87
  };
94
88
 
95
89
  const handleGranted = async (event) => {