@jskit-ai/google-rewarded-core 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +98 -0
- package/docs/protecting-server-actions.md +190 -0
- package/package.descriptor.mjs +186 -0
- package/package.json +10 -0
- package/src/server/GoogleRewardedCoreProvider.js +51 -0
- package/src/server/actions.js +102 -0
- package/src/server/inputSchemas.js +394 -0
- package/src/server/providerConfigs/GoogleRewardedProviderConfigsProvider.js +98 -0
- package/src/server/providerConfigs/actions.js +157 -0
- package/src/server/providerConfigs/registerRoutes.js +176 -0
- package/src/server/providerConfigs/repository.js +107 -0
- package/src/server/providerConfigs/service.js +61 -0
- package/src/server/registerRoutes.js +169 -0
- package/src/server/rules/GoogleRewardedRulesProvider.js +98 -0
- package/src/server/rules/actions.js +157 -0
- package/src/server/rules/registerRoutes.js +176 -0
- package/src/server/rules/repository.js +107 -0
- package/src/server/rules/service.js +61 -0
- package/src/server/service.js +552 -0
- package/src/server/support/requireGoogleRewardedUnlock.js +142 -0
- package/src/server/unlockReceipts/GoogleRewardedUnlockReceiptsProvider.js +98 -0
- package/src/server/unlockReceipts/actions.js +157 -0
- package/src/server/unlockReceipts/registerRoutes.js +176 -0
- package/src/server/unlockReceipts/repository.js +107 -0
- package/src/server/unlockReceipts/service.js +61 -0
- package/src/server/watchSessions/GoogleRewardedWatchSessionsProvider.js +98 -0
- package/src/server/watchSessions/actions.js +157 -0
- package/src/server/watchSessions/registerRoutes.js +176 -0
- package/src/server/watchSessions/repository.js +107 -0
- package/src/server/watchSessions/service.js +61 -0
- package/src/shared/googleRewardedProviderConfigResource.js +94 -0
- package/src/shared/googleRewardedRuleResource.js +136 -0
- package/src/shared/googleRewardedUnlockReceiptResource.js +113 -0
- package/src/shared/googleRewardedWatchSessionResource.js +139 -0
- package/src/shared/index.js +12 -0
- package/templates/migrations/google_rewarded_provider_configs_initial.cjs +27 -0
- package/templates/migrations/google_rewarded_rules_initial.cjs +31 -0
- package/templates/migrations/google_rewarded_unlock_receipts_initial.cjs +35 -0
- package/templates/migrations/google_rewarded_watch_sessions_initial.cjs +36 -0
- package/test/requireGoogleRewardedUnlock.test.js +274 -0
- package/test/routes.test.js +248 -0
- package/test/service.test.js +315 -0
package/README.md
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# @jskit-ai/google-rewarded-core
|
|
2
|
+
|
|
3
|
+
Server runtime for Google rewarded unlock gates.
|
|
4
|
+
|
|
5
|
+
## Package Shape
|
|
6
|
+
|
|
7
|
+
This package installs:
|
|
8
|
+
|
|
9
|
+
- four CRUD-owned server providers, one per persisted table
|
|
10
|
+
- one workflow provider for the rewarded gate API
|
|
11
|
+
|
|
12
|
+
The persisted tables are:
|
|
13
|
+
|
|
14
|
+
- `google_rewarded_rules`
|
|
15
|
+
- `google_rewarded_provider_configs`
|
|
16
|
+
- `google_rewarded_watch_sessions`
|
|
17
|
+
- `google_rewarded_unlock_receipts`
|
|
18
|
+
|
|
19
|
+
The package keeps the CRUD ownership strict:
|
|
20
|
+
|
|
21
|
+
- rules and provider configs are `workspace`-owned
|
|
22
|
+
- watch sessions and unlock receipts are `workspace_user`-owned
|
|
23
|
+
|
|
24
|
+
Every owned row carries direct owner columns. The module does not rely on inherited ownership through parent joins.
|
|
25
|
+
|
|
26
|
+
## What It Does
|
|
27
|
+
|
|
28
|
+
The workflow provider exposes four workspace-scoped app routes:
|
|
29
|
+
|
|
30
|
+
- `GET /api/w/:workspaceSlug/google-rewarded/current`
|
|
31
|
+
- `POST /api/w/:workspaceSlug/google-rewarded/start`
|
|
32
|
+
- `POST /api/w/:workspaceSlug/google-rewarded/grant`
|
|
33
|
+
- `POST /api/w/:workspaceSlug/google-rewarded/close`
|
|
34
|
+
|
|
35
|
+
These are plain workflow endpoints, not CRUD JSON:API endpoints.
|
|
36
|
+
|
|
37
|
+
The flow is:
|
|
38
|
+
|
|
39
|
+
1. `current` decides whether the gate is enabled, blocked, or already unlocked.
|
|
40
|
+
2. `start` creates a watch session when a reward is required.
|
|
41
|
+
3. `grant` marks the session rewarded and creates an unlock receipt.
|
|
42
|
+
4. `close` closes a started session without granting access.
|
|
43
|
+
|
|
44
|
+
Day 0 is intentionally app-surface-only for the rewarded workflow. Rules and provider configs should therefore use `surface = "app"` for the active gate rows.
|
|
45
|
+
|
|
46
|
+
## Required Data
|
|
47
|
+
|
|
48
|
+
Day-0 configuration lives in the CRUD-owned tables.
|
|
49
|
+
|
|
50
|
+
At minimum, apps need:
|
|
51
|
+
|
|
52
|
+
- a `google_rewarded_rules` row for the target `gateKey`
|
|
53
|
+
- a matching enabled `google_rewarded_provider_configs` row for the surface
|
|
54
|
+
|
|
55
|
+
Important config fields:
|
|
56
|
+
|
|
57
|
+
- `google_rewarded_rules.gate_key`
|
|
58
|
+
- `google_rewarded_rules.surface`
|
|
59
|
+
- `google_rewarded_rules.unlock_minutes`
|
|
60
|
+
- `google_rewarded_rules.cooldown_minutes`
|
|
61
|
+
- `google_rewarded_rules.daily_limit`
|
|
62
|
+
- `google_rewarded_provider_configs.surface`
|
|
63
|
+
- `google_rewarded_provider_configs.ad_unit_path`
|
|
64
|
+
- `google_rewarded_provider_configs.script_mode`
|
|
65
|
+
|
|
66
|
+
Day 0 assumes GPT rewarded ads for web, so `script_mode` should stay aligned with that flow.
|
|
67
|
+
|
|
68
|
+
## Protecting Server Features
|
|
69
|
+
|
|
70
|
+
Protected server mutations should use the exported helper:
|
|
71
|
+
|
|
72
|
+
```js
|
|
73
|
+
import { requireGoogleRewardedUnlock } from "@jskit-ai/google-rewarded-core/server/requireGoogleRewardedUnlock";
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
The dedicated manual page is:
|
|
77
|
+
|
|
78
|
+
- [docs/protecting-server-actions.md](/home/merc/Development/current/jskit-ai/packages/google-rewarded-core/docs/protecting-server-actions.md)
|
|
79
|
+
|
|
80
|
+
That page shows the exact service and provider wiring pattern.
|
|
81
|
+
|
|
82
|
+
## Policy Model
|
|
83
|
+
|
|
84
|
+
This module is designed for rewarded unlocks, not for blocking all normal app use on boot.
|
|
85
|
+
|
|
86
|
+
Recommended usage:
|
|
87
|
+
|
|
88
|
+
- unlock bonus actions
|
|
89
|
+
- unlock extra quota
|
|
90
|
+
- unlock a temporary feature window
|
|
91
|
+
|
|
92
|
+
Do not treat it as a hard requirement for baseline product use unless the ad provider policy clearly allows that.
|
|
93
|
+
|
|
94
|
+
## Install Notes
|
|
95
|
+
|
|
96
|
+
When an app adds this package, JSKIT installs the four schema migrations from `templates/migrations/`.
|
|
97
|
+
|
|
98
|
+
The package does not add day-0 settings pages automatically. Configuration can stay manual or be layered with app-specific UI later.
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
# Protecting Server Actions With `requireGoogleRewardedUnlock()`
|
|
2
|
+
|
|
3
|
+
This is the manual page for the server helper exported by:
|
|
4
|
+
|
|
5
|
+
```js
|
|
6
|
+
@jskit-ai/google-rewarded-core/server/requireGoogleRewardedUnlock
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
Use this helper when a feature is:
|
|
10
|
+
|
|
11
|
+
- allowed in principle for the actor
|
|
12
|
+
- but temporarily gated behind a rewarded unlock
|
|
13
|
+
|
|
14
|
+
Do not use it as a permission system.
|
|
15
|
+
|
|
16
|
+
The correct split is:
|
|
17
|
+
|
|
18
|
+
- permissions decide whether the actor may ever do the thing
|
|
19
|
+
- rewarded gates decide whether the actor must unlock the thing right now
|
|
20
|
+
|
|
21
|
+
## What The Helper Does
|
|
22
|
+
|
|
23
|
+
`requireGoogleRewardedUnlock()` calls `google-rewarded.core.service.getCurrentState(...)` and then enforces one simple rule:
|
|
24
|
+
|
|
25
|
+
- if the gate is already unlocked, it returns the gate state
|
|
26
|
+
- if the gate is not configured and `requireConfigured` is not enabled, it returns the gate state
|
|
27
|
+
- otherwise it throws an `AppError`
|
|
28
|
+
|
|
29
|
+
This means the helper is a truth-enforcement seam for protected server operations.
|
|
30
|
+
|
|
31
|
+
The UI should still call the web runtime first for user experience, but the protected server operation must also check the gate so users cannot bypass it by calling the endpoint directly.
|
|
32
|
+
|
|
33
|
+
## Import Path
|
|
34
|
+
|
|
35
|
+
```js
|
|
36
|
+
import { requireGoogleRewardedUnlock } from "@jskit-ai/google-rewarded-core/server/requireGoogleRewardedUnlock";
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Basic Service Pattern
|
|
40
|
+
|
|
41
|
+
Inject `google-rewarded.core.service` into your own feature service, then call the helper before the protected mutation.
|
|
42
|
+
|
|
43
|
+
Example:
|
|
44
|
+
|
|
45
|
+
```js
|
|
46
|
+
import { requireGoogleRewardedUnlock } from "@jskit-ai/google-rewarded-core/server/requireGoogleRewardedUnlock";
|
|
47
|
+
|
|
48
|
+
function createProgressLoggingService({
|
|
49
|
+
googleRewardedService,
|
|
50
|
+
workoutLogRepository
|
|
51
|
+
} = {}) {
|
|
52
|
+
async function logProgress(input = {}, options = {}) {
|
|
53
|
+
await requireGoogleRewardedUnlock(
|
|
54
|
+
googleRewardedService,
|
|
55
|
+
{
|
|
56
|
+
gateKey: "progress-logging",
|
|
57
|
+
workspaceSlug: input.workspaceSlug
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
context: options.context,
|
|
61
|
+
errorMessage: "Watch a rewarded ad before logging progress."
|
|
62
|
+
}
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
return workoutLogRepository.create(input, options);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return Object.freeze({
|
|
69
|
+
logProgress
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Provider Wiring Pattern
|
|
75
|
+
|
|
76
|
+
Inject the rewarded service from the container the same way as any other JSKIT runtime service.
|
|
77
|
+
|
|
78
|
+
Example:
|
|
79
|
+
|
|
80
|
+
```js
|
|
81
|
+
app.service(
|
|
82
|
+
"convict.progress-logging.service",
|
|
83
|
+
(scope) => createProgressLoggingService({
|
|
84
|
+
googleRewardedService: scope.make("google-rewarded.core.service"),
|
|
85
|
+
workoutLogRepository: scope.make("convict.workout-log.repository")
|
|
86
|
+
})
|
|
87
|
+
);
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Exact Helper Signature
|
|
91
|
+
|
|
92
|
+
```js
|
|
93
|
+
await requireGoogleRewardedUnlock(
|
|
94
|
+
googleRewardedService,
|
|
95
|
+
{
|
|
96
|
+
gateKey,
|
|
97
|
+
workspaceSlug
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
context,
|
|
101
|
+
requireConfigured,
|
|
102
|
+
errorCode,
|
|
103
|
+
errorMessage
|
|
104
|
+
}
|
|
105
|
+
);
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Arguments:
|
|
109
|
+
|
|
110
|
+
- `googleRewardedService`
|
|
111
|
+
- must expose `getCurrentState(input, { context })`
|
|
112
|
+
- first object
|
|
113
|
+
- `gateKey`: required gate identifier
|
|
114
|
+
- `workspaceSlug`: required for the current workspace gate
|
|
115
|
+
- second object
|
|
116
|
+
- `context`: the normal JSKIT action/service context
|
|
117
|
+
- `requireConfigured`: fail closed when no rule/provider config exists
|
|
118
|
+
- `errorCode`: optional override for the thrown `AppError.code`
|
|
119
|
+
- `errorMessage`: optional override for the thrown `AppError.message`
|
|
120
|
+
|
|
121
|
+
## Default Behavior
|
|
122
|
+
|
|
123
|
+
The helper is intentionally permissive when the rewarded gate is not configured.
|
|
124
|
+
|
|
125
|
+
By default:
|
|
126
|
+
|
|
127
|
+
- `reason = "rule-not-configured"` passes
|
|
128
|
+
- `reason = "provider-not-configured"` passes
|
|
129
|
+
|
|
130
|
+
Why:
|
|
131
|
+
|
|
132
|
+
- day-0 apps may install the package before creating live rules/config rows
|
|
133
|
+
- you do not want every protected feature to break during setup or partial rollout
|
|
134
|
+
|
|
135
|
+
If you want the protected operation to fail closed until configuration exists, set:
|
|
136
|
+
|
|
137
|
+
```js
|
|
138
|
+
requireConfigured: true
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## When The Helper Throws
|
|
142
|
+
|
|
143
|
+
The helper throws `AppError` with `details.rewardedGate` containing the full gate state.
|
|
144
|
+
|
|
145
|
+
Important built-in failure cases:
|
|
146
|
+
|
|
147
|
+
- `reward-required`
|
|
148
|
+
- status: `423`
|
|
149
|
+
- code: `google_rewarded_unlock_required`
|
|
150
|
+
- `cooldown-active`
|
|
151
|
+
- status: `423`
|
|
152
|
+
- code: `google_rewarded_cooldown_active`
|
|
153
|
+
- `daily-limit-reached`
|
|
154
|
+
- status: `423`
|
|
155
|
+
- code: `google_rewarded_daily_limit_reached`
|
|
156
|
+
- `rule-not-configured` or `provider-not-configured` with `requireConfigured: true`
|
|
157
|
+
- status: `503`
|
|
158
|
+
- code: `google_rewarded_not_configured`
|
|
159
|
+
|
|
160
|
+
## What The Helper Returns
|
|
161
|
+
|
|
162
|
+
On success, the helper returns the gate state from `googleRewardedService.getCurrentState(...)`.
|
|
163
|
+
|
|
164
|
+
That lets your service inspect the unlock window if it wants to log or branch on it, for example:
|
|
165
|
+
|
|
166
|
+
```js
|
|
167
|
+
const gateState = await requireGoogleRewardedUnlock(...);
|
|
168
|
+
const unlockedUntil = gateState.unlock?.unlockedUntil || null;
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Recommended Calling Order
|
|
172
|
+
|
|
173
|
+
For a protected feature operation:
|
|
174
|
+
|
|
175
|
+
1. run normal permission / ownership checks
|
|
176
|
+
2. run `requireGoogleRewardedUnlock(...)`
|
|
177
|
+
3. perform the real mutation
|
|
178
|
+
|
|
179
|
+
Do not invert that order.
|
|
180
|
+
|
|
181
|
+
## What Not To Do
|
|
182
|
+
|
|
183
|
+
Do not:
|
|
184
|
+
|
|
185
|
+
- model rewarded gates as permissions
|
|
186
|
+
- skip the server check because the client already opened the gate
|
|
187
|
+
- rely on route visibility as the rewarded gate
|
|
188
|
+
- duplicate the raw `reason` checks in every feature service
|
|
189
|
+
|
|
190
|
+
Use the helper instead of open-coding that logic.
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
export default Object.freeze({
|
|
2
|
+
packageVersion: 1,
|
|
3
|
+
packageId: "@jskit-ai/google-rewarded-core",
|
|
4
|
+
version: "0.1.1",
|
|
5
|
+
kind: "runtime",
|
|
6
|
+
description: "Google rewarded workflow runtime plus internal CRUD providers for rules, provider configs, watch sessions, and unlock receipts.",
|
|
7
|
+
dependsOn: [
|
|
8
|
+
"@jskit-ai/auth-core",
|
|
9
|
+
"@jskit-ai/crud-core",
|
|
10
|
+
"@jskit-ai/database-runtime",
|
|
11
|
+
"@jskit-ai/http-runtime",
|
|
12
|
+
"@jskit-ai/json-rest-api-core",
|
|
13
|
+
"@jskit-ai/kernel",
|
|
14
|
+
"@jskit-ai/resource-crud-core",
|
|
15
|
+
"@jskit-ai/workspaces-core"
|
|
16
|
+
],
|
|
17
|
+
capabilities: {
|
|
18
|
+
provides: [
|
|
19
|
+
"crud.google-rewarded-rules",
|
|
20
|
+
"crud.google-rewarded-provider-configs",
|
|
21
|
+
"crud.google-rewarded-watch-sessions",
|
|
22
|
+
"crud.google-rewarded-unlock-receipts",
|
|
23
|
+
"google-rewarded.core"
|
|
24
|
+
],
|
|
25
|
+
requires: [
|
|
26
|
+
"runtime.actions",
|
|
27
|
+
"runtime.database",
|
|
28
|
+
"auth.policy",
|
|
29
|
+
"json-rest-api.core"
|
|
30
|
+
]
|
|
31
|
+
},
|
|
32
|
+
runtime: {
|
|
33
|
+
server: {
|
|
34
|
+
providers: [
|
|
35
|
+
{
|
|
36
|
+
entrypoint: "src/server/rules/GoogleRewardedRulesProvider.js",
|
|
37
|
+
export: "GoogleRewardedRulesProvider"
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
entrypoint: "src/server/providerConfigs/GoogleRewardedProviderConfigsProvider.js",
|
|
41
|
+
export: "GoogleRewardedProviderConfigsProvider"
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
entrypoint: "src/server/watchSessions/GoogleRewardedWatchSessionsProvider.js",
|
|
45
|
+
export: "GoogleRewardedWatchSessionsProvider"
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
entrypoint: "src/server/unlockReceipts/GoogleRewardedUnlockReceiptsProvider.js",
|
|
49
|
+
export: "GoogleRewardedUnlockReceiptsProvider"
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
entrypoint: "src/server/GoogleRewardedCoreProvider.js",
|
|
53
|
+
export: "GoogleRewardedCoreProvider"
|
|
54
|
+
}
|
|
55
|
+
]
|
|
56
|
+
},
|
|
57
|
+
client: {
|
|
58
|
+
providers: []
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
metadata: {
|
|
62
|
+
jskit: {
|
|
63
|
+
scaffoldShape: "crud-server-v1",
|
|
64
|
+
tableOwnership: {
|
|
65
|
+
tables: [
|
|
66
|
+
{
|
|
67
|
+
tableName: "google_rewarded_rules",
|
|
68
|
+
provenance: "crud-server-generator",
|
|
69
|
+
ownerKind: "crud-package",
|
|
70
|
+
providerEntrypoint: "src/server/rules/GoogleRewardedRulesProvider.js",
|
|
71
|
+
ownershipFilter: "workspace"
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
tableName: "google_rewarded_provider_configs",
|
|
75
|
+
provenance: "crud-server-generator",
|
|
76
|
+
ownerKind: "crud-package",
|
|
77
|
+
providerEntrypoint: "src/server/providerConfigs/GoogleRewardedProviderConfigsProvider.js",
|
|
78
|
+
ownershipFilter: "workspace"
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
tableName: "google_rewarded_watch_sessions",
|
|
82
|
+
provenance: "crud-server-generator",
|
|
83
|
+
ownerKind: "crud-package",
|
|
84
|
+
providerEntrypoint: "src/server/watchSessions/GoogleRewardedWatchSessionsProvider.js",
|
|
85
|
+
ownershipFilter: "workspace_user"
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
tableName: "google_rewarded_unlock_receipts",
|
|
89
|
+
provenance: "crud-server-generator",
|
|
90
|
+
ownerKind: "crud-package",
|
|
91
|
+
providerEntrypoint: "src/server/unlockReceipts/GoogleRewardedUnlockReceiptsProvider.js",
|
|
92
|
+
ownershipFilter: "workspace_user"
|
|
93
|
+
}
|
|
94
|
+
]
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
apiSummary: {
|
|
98
|
+
surfaces: [
|
|
99
|
+
{
|
|
100
|
+
subpath: "./shared",
|
|
101
|
+
summary: "Exports Google rewarded shared CRUD resources."
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
subpath: "./server/actions",
|
|
105
|
+
summary: "Exports Google rewarded workflow action identifiers and validators."
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
subpath: "./server/requireGoogleRewardedUnlock",
|
|
109
|
+
summary: "Exports the server helper that enforces a rewarded unlock before a protected feature action continues."
|
|
110
|
+
}
|
|
111
|
+
],
|
|
112
|
+
containerTokens: {
|
|
113
|
+
server: [
|
|
114
|
+
"repository.google_rewarded_rules",
|
|
115
|
+
"crud.google_rewarded_rules",
|
|
116
|
+
"repository.google_rewarded_provider_configs",
|
|
117
|
+
"crud.google_rewarded_provider_configs",
|
|
118
|
+
"repository.google_rewarded_watch_sessions",
|
|
119
|
+
"crud.google_rewarded_watch_sessions",
|
|
120
|
+
"repository.google_rewarded_unlock_receipts",
|
|
121
|
+
"crud.google_rewarded_unlock_receipts",
|
|
122
|
+
"google-rewarded.core.service"
|
|
123
|
+
],
|
|
124
|
+
client: []
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
mutations: {
|
|
129
|
+
dependencies: {
|
|
130
|
+
runtime: {
|
|
131
|
+
"@jskit-ai/auth-core": "0.1.63",
|
|
132
|
+
"@jskit-ai/crud-core": "0.1.72",
|
|
133
|
+
"@jskit-ai/database-runtime": "0.1.64",
|
|
134
|
+
"@jskit-ai/http-runtime": "0.1.63",
|
|
135
|
+
"@jskit-ai/json-rest-api-core": "0.1.9",
|
|
136
|
+
"@jskit-ai/kernel": "0.1.64",
|
|
137
|
+
"@jskit-ai/resource-crud-core": "0.1.9",
|
|
138
|
+
"@jskit-ai/workspaces-core": "0.1.40"
|
|
139
|
+
},
|
|
140
|
+
dev: {}
|
|
141
|
+
},
|
|
142
|
+
packageJson: {
|
|
143
|
+
scripts: {}
|
|
144
|
+
},
|
|
145
|
+
procfile: {},
|
|
146
|
+
files: [
|
|
147
|
+
{
|
|
148
|
+
op: "install-migration",
|
|
149
|
+
from: "templates/migrations/google_rewarded_rules_initial.cjs",
|
|
150
|
+
toDir: "migrations",
|
|
151
|
+
extension: ".cjs",
|
|
152
|
+
reason: "Install Google rewarded rules schema migration.",
|
|
153
|
+
category: "google-rewarded",
|
|
154
|
+
id: "google-rewarded-rules-initial-schema"
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
op: "install-migration",
|
|
158
|
+
from: "templates/migrations/google_rewarded_provider_configs_initial.cjs",
|
|
159
|
+
toDir: "migrations",
|
|
160
|
+
extension: ".cjs",
|
|
161
|
+
reason: "Install Google rewarded provider config schema migration.",
|
|
162
|
+
category: "google-rewarded",
|
|
163
|
+
id: "google-rewarded-provider-configs-initial-schema"
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
op: "install-migration",
|
|
167
|
+
from: "templates/migrations/google_rewarded_watch_sessions_initial.cjs",
|
|
168
|
+
toDir: "migrations",
|
|
169
|
+
extension: ".cjs",
|
|
170
|
+
reason: "Install Google rewarded watch sessions schema migration.",
|
|
171
|
+
category: "google-rewarded",
|
|
172
|
+
id: "google-rewarded-watch-sessions-initial-schema"
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
op: "install-migration",
|
|
176
|
+
from: "templates/migrations/google_rewarded_unlock_receipts_initial.cjs",
|
|
177
|
+
toDir: "migrations",
|
|
178
|
+
extension: ".cjs",
|
|
179
|
+
reason: "Install Google rewarded unlock receipts schema migration.",
|
|
180
|
+
category: "google-rewarded",
|
|
181
|
+
id: "google-rewarded-unlock-receipts-initial-schema"
|
|
182
|
+
}
|
|
183
|
+
],
|
|
184
|
+
text: []
|
|
185
|
+
}
|
|
186
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@jskit-ai/google-rewarded-core",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"exports": {
|
|
6
|
+
"./shared": "./src/shared/index.js",
|
|
7
|
+
"./server/actions": "./src/server/actions.js",
|
|
8
|
+
"./server/requireGoogleRewardedUnlock": "./src/server/support/requireGoogleRewardedUnlock.js"
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { withActionDefaults } from "@jskit-ai/kernel/shared/actions";
|
|
2
|
+
|
|
3
|
+
import { createService } from "./service.js";
|
|
4
|
+
import { googleRewardedActions } from "./actions.js";
|
|
5
|
+
import { registerRoutes } from "./registerRoutes.js";
|
|
6
|
+
|
|
7
|
+
class GoogleRewardedCoreProvider {
|
|
8
|
+
static id = "google-rewarded.core";
|
|
9
|
+
|
|
10
|
+
static dependsOn = ["runtime.actions"];
|
|
11
|
+
|
|
12
|
+
register(app) {
|
|
13
|
+
if (
|
|
14
|
+
!app ||
|
|
15
|
+
typeof app.singleton !== "function" ||
|
|
16
|
+
typeof app.service !== "function" ||
|
|
17
|
+
typeof app.actions !== "function"
|
|
18
|
+
) {
|
|
19
|
+
throw new Error("GoogleRewardedCoreProvider requires application singleton()/service()/actions().");
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
app.service(
|
|
23
|
+
"google-rewarded.core.service",
|
|
24
|
+
(scope) => createService({
|
|
25
|
+
googleRewardedRulesRepository: scope.make("repository.google_rewarded_rules"),
|
|
26
|
+
googleRewardedProviderConfigsRepository: scope.make("repository.google_rewarded_provider_configs"),
|
|
27
|
+
googleRewardedWatchSessionsRepository: scope.make("repository.google_rewarded_watch_sessions"),
|
|
28
|
+
googleRewardedUnlockReceiptsRepository: scope.make("repository.google_rewarded_unlock_receipts")
|
|
29
|
+
})
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
app.actions(
|
|
33
|
+
withActionDefaults(googleRewardedActions, {
|
|
34
|
+
domain: "google-rewarded",
|
|
35
|
+
dependencies: {
|
|
36
|
+
googleRewardedService: "google-rewarded.core.service"
|
|
37
|
+
}
|
|
38
|
+
})
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
boot(app) {
|
|
43
|
+
registerRoutes(app, {
|
|
44
|
+
routeOwnershipFilter: "workspace_user",
|
|
45
|
+
routeSurface: "app",
|
|
46
|
+
routeRelativePath: "google-rewarded"
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export { GoogleRewardedCoreProvider };
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import {
|
|
2
|
+
currentQueryInputValidator,
|
|
3
|
+
startCommandInputValidator,
|
|
4
|
+
grantCommandInputValidator,
|
|
5
|
+
closeCommandInputValidator,
|
|
6
|
+
currentStateOutputValidator,
|
|
7
|
+
startGateOutputValidator,
|
|
8
|
+
grantRewardOutputValidator,
|
|
9
|
+
closeSessionOutputValidator
|
|
10
|
+
} from "./inputSchemas.js";
|
|
11
|
+
|
|
12
|
+
const ACTION_CURRENT = "google-rewarded.current.read";
|
|
13
|
+
const ACTION_START = "google-rewarded.start";
|
|
14
|
+
const ACTION_GRANT = "google-rewarded.grant";
|
|
15
|
+
const ACTION_CLOSE = "google-rewarded.close";
|
|
16
|
+
|
|
17
|
+
const googleRewardedActions = Object.freeze([
|
|
18
|
+
{
|
|
19
|
+
id: ACTION_CURRENT,
|
|
20
|
+
version: 1,
|
|
21
|
+
kind: "query",
|
|
22
|
+
channels: ["api", "automation", "internal"],
|
|
23
|
+
surfacesFrom: "enabled",
|
|
24
|
+
input: currentQueryInputValidator,
|
|
25
|
+
output: currentStateOutputValidator,
|
|
26
|
+
idempotency: "none",
|
|
27
|
+
audit: {
|
|
28
|
+
actionName: ACTION_CURRENT
|
|
29
|
+
},
|
|
30
|
+
observability: {},
|
|
31
|
+
async execute(input, context, deps) {
|
|
32
|
+
return deps.googleRewardedService.getCurrentState(input, {
|
|
33
|
+
context
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
id: ACTION_START,
|
|
39
|
+
version: 1,
|
|
40
|
+
kind: "command",
|
|
41
|
+
channels: ["api", "automation", "internal"],
|
|
42
|
+
surfacesFrom: "enabled",
|
|
43
|
+
input: startCommandInputValidator,
|
|
44
|
+
output: startGateOutputValidator,
|
|
45
|
+
idempotency: "optional",
|
|
46
|
+
audit: {
|
|
47
|
+
actionName: ACTION_START
|
|
48
|
+
},
|
|
49
|
+
observability: {},
|
|
50
|
+
async execute(input, context, deps) {
|
|
51
|
+
return deps.googleRewardedService.startGate(input, {
|
|
52
|
+
context
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
id: ACTION_GRANT,
|
|
58
|
+
version: 1,
|
|
59
|
+
kind: "command",
|
|
60
|
+
channels: ["api", "automation", "internal"],
|
|
61
|
+
surfacesFrom: "enabled",
|
|
62
|
+
input: grantCommandInputValidator,
|
|
63
|
+
output: grantRewardOutputValidator,
|
|
64
|
+
idempotency: "optional",
|
|
65
|
+
audit: {
|
|
66
|
+
actionName: ACTION_GRANT
|
|
67
|
+
},
|
|
68
|
+
observability: {},
|
|
69
|
+
async execute(input, context, deps) {
|
|
70
|
+
return deps.googleRewardedService.grantReward(input, {
|
|
71
|
+
context
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
id: ACTION_CLOSE,
|
|
77
|
+
version: 1,
|
|
78
|
+
kind: "command",
|
|
79
|
+
channels: ["api", "automation", "internal"],
|
|
80
|
+
surfacesFrom: "enabled",
|
|
81
|
+
input: closeCommandInputValidator,
|
|
82
|
+
output: closeSessionOutputValidator,
|
|
83
|
+
idempotency: "optional",
|
|
84
|
+
audit: {
|
|
85
|
+
actionName: ACTION_CLOSE
|
|
86
|
+
},
|
|
87
|
+
observability: {},
|
|
88
|
+
async execute(input, context, deps) {
|
|
89
|
+
return deps.googleRewardedService.closeSession(input, {
|
|
90
|
+
context
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
]);
|
|
95
|
+
|
|
96
|
+
export {
|
|
97
|
+
ACTION_CURRENT,
|
|
98
|
+
ACTION_START,
|
|
99
|
+
ACTION_GRANT,
|
|
100
|
+
ACTION_CLOSE,
|
|
101
|
+
googleRewardedActions
|
|
102
|
+
};
|