@suucha/ads-adsense 0.1.0
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/LICENSE +21 -0
- package/README.md +87 -0
- package/dist/index.cjs +119 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +63 -0
- package/dist/index.d.ts +63 -0
- package/dist/index.js +117 -0
- package/dist/index.js.map +1 -0
- package/package.json +48 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Suucha Studio
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# @suucha/ads-adsense
|
|
2
|
+
|
|
3
|
+
[](../../LICENSE)
|
|
4
|
+
|
|
5
|
+
Google AdSense ad manager implementation for Suucha Web SDK. Dynamically loads `adsbygoogle.js` and mounts ad slots into DOM containers.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pnpm add @suucha/core @suucha/ads-adsense
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
### Auto Ads (simplest)
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
import { suucha } from '@suucha/core';
|
|
19
|
+
import { AdSenseManager } from '@suucha/ads-adsense';
|
|
20
|
+
|
|
21
|
+
const ads = new AdSenseManager({
|
|
22
|
+
client: 'ca-pub-1234567890123456',
|
|
23
|
+
autoAds: true,
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
suucha.enableAds(ads);
|
|
27
|
+
// AdSense automatically picks ad placements
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Manual Slots
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
const ads = new AdSenseManager({
|
|
34
|
+
client: 'ca-pub-1234567890123456',
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
suucha.enableAds(ads);
|
|
38
|
+
|
|
39
|
+
const handle = await ads.mountSlot({
|
|
40
|
+
container: '#ad-banner', // CSS selector or HTMLElement
|
|
41
|
+
slot: '1234567890',
|
|
42
|
+
format: 'horizontal',
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// Refresh slot
|
|
46
|
+
handle.refresh();
|
|
47
|
+
|
|
48
|
+
// Tear down
|
|
49
|
+
ads.unmountSlot(handle);
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Consent / GDPR
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
const ads = new AdSenseManager({
|
|
56
|
+
client: 'ca-pub-...',
|
|
57
|
+
deferUntilConsent: true,
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// Script not loaded yet
|
|
61
|
+
suucha.enableAds(ads);
|
|
62
|
+
|
|
63
|
+
// After CMP grants consent:
|
|
64
|
+
suucha.setConsent(true);
|
|
65
|
+
ads.load();
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Options
|
|
69
|
+
|
|
70
|
+
| Option | Default | Description |
|
|
71
|
+
|---|---|---|
|
|
72
|
+
| `client` | (required) | Publisher ID (`ca-pub-XXXX`) |
|
|
73
|
+
| `autoAds` | `false` | Enable AdSense auto-ad placement |
|
|
74
|
+
| `deferUntilConsent` | `false` | Skip script load until `load()` called |
|
|
75
|
+
|
|
76
|
+
## Slot Options
|
|
77
|
+
|
|
78
|
+
| Option | Default | Description |
|
|
79
|
+
|---|---|---|
|
|
80
|
+
| `container` | (required) | CSS selector or HTMLElement |
|
|
81
|
+
| `slot` | - | Ad unit ID |
|
|
82
|
+
| `format` | `'auto'` | `'auto'` / `'horizontal'` / `'vertical'` / `'rectangle'` |
|
|
83
|
+
| `responsive` | `true` | Fill container width |
|
|
84
|
+
|
|
85
|
+
## License
|
|
86
|
+
|
|
87
|
+
MIT © Suucha Studio
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
5
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
6
|
+
|
|
7
|
+
// src/index.ts
|
|
8
|
+
var DEFAULT_SCRIPT_SRC = "https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js";
|
|
9
|
+
var nextSlotId = 1;
|
|
10
|
+
var AdSenseManager = class {
|
|
11
|
+
constructor(options) {
|
|
12
|
+
__publicField(this, "options");
|
|
13
|
+
__publicField(this, "loaded", false);
|
|
14
|
+
__publicField(this, "slots", /* @__PURE__ */ new Map());
|
|
15
|
+
if (!options.client || !options.client.startsWith("ca-pub-")) {
|
|
16
|
+
throw new Error(
|
|
17
|
+
`[AdSenseManager] client must start with 'ca-pub-', got: ${options.client}`
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
this.options = {
|
|
21
|
+
autoAds: false,
|
|
22
|
+
deferUntilConsent: false,
|
|
23
|
+
scriptSrc: DEFAULT_SCRIPT_SRC,
|
|
24
|
+
...options
|
|
25
|
+
};
|
|
26
|
+
if (!this.options.deferUntilConsent) {
|
|
27
|
+
this.load();
|
|
28
|
+
}
|
|
29
|
+
if (this.options.autoAds) {
|
|
30
|
+
this.enableAutoAds();
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* 加载 AdSense 脚本
|
|
35
|
+
*/
|
|
36
|
+
load() {
|
|
37
|
+
if (this.loaded) return;
|
|
38
|
+
if (typeof document === "undefined") return;
|
|
39
|
+
const script = document.createElement("script");
|
|
40
|
+
script.async = true;
|
|
41
|
+
script.src = `${this.options.scriptSrc}?client=${this.options.client}`;
|
|
42
|
+
script.crossOrigin = "anonymous";
|
|
43
|
+
document.head.appendChild(script);
|
|
44
|
+
window.adsbygoogle = window.adsbygoogle || [];
|
|
45
|
+
this.loaded = true;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* 启用自动广告(AdSense 自动选择位置)
|
|
49
|
+
*/
|
|
50
|
+
enableAutoAds() {
|
|
51
|
+
if (typeof window === "undefined" || !window.adsbygoogle) return;
|
|
52
|
+
window.adsbygoogle.push({ google_ad_client: this.options.client });
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* 挂载广告位到 DOM
|
|
56
|
+
*/
|
|
57
|
+
async mountSlot(slotOptions) {
|
|
58
|
+
if (typeof document === "undefined") {
|
|
59
|
+
throw new Error("[AdSenseManager] mountSlot requires a browser environment");
|
|
60
|
+
}
|
|
61
|
+
const container = typeof slotOptions.container === "string" ? document.querySelector(slotOptions.container) : slotOptions.container;
|
|
62
|
+
if (!container) {
|
|
63
|
+
throw new Error(
|
|
64
|
+
`[AdSenseManager] Container not found: ${slotOptions.container}`
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
const ins = document.createElement("ins");
|
|
68
|
+
ins.className = "adsbygoogle";
|
|
69
|
+
ins.style.display = "block";
|
|
70
|
+
ins.setAttribute("data-ad-client", this.options.client);
|
|
71
|
+
if (slotOptions.slot) {
|
|
72
|
+
ins.setAttribute("data-ad-slot", slotOptions.slot);
|
|
73
|
+
}
|
|
74
|
+
ins.setAttribute(
|
|
75
|
+
"data-ad-format",
|
|
76
|
+
slotOptions.format ?? "auto"
|
|
77
|
+
);
|
|
78
|
+
if (slotOptions.responsive !== false) {
|
|
79
|
+
ins.setAttribute("data-full-width-responsive", "true");
|
|
80
|
+
}
|
|
81
|
+
container.appendChild(ins);
|
|
82
|
+
if (window.adsbygoogle) {
|
|
83
|
+
window.adsbygoogle.push({});
|
|
84
|
+
}
|
|
85
|
+
const id = `adsense_slot_${nextSlotId++}`;
|
|
86
|
+
const handle = {
|
|
87
|
+
id,
|
|
88
|
+
slot: slotOptions.slot ?? "",
|
|
89
|
+
refresh: () => {
|
|
90
|
+
if (window.adsbygoogle) {
|
|
91
|
+
window.adsbygoogle.push({ refresh: () => {
|
|
92
|
+
} });
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
destroy: () => {
|
|
96
|
+
ins.remove();
|
|
97
|
+
this.slots.delete(id);
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
this.slots.set(id, handle);
|
|
101
|
+
return handle;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* 卸载广告位
|
|
105
|
+
*/
|
|
106
|
+
unmountSlot(handle) {
|
|
107
|
+
handle.destroy();
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* 刷新广告位(重新竞价)
|
|
111
|
+
*/
|
|
112
|
+
refresh(handle) {
|
|
113
|
+
handle.refresh();
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
exports.AdSenseManager = AdSenseManager;
|
|
118
|
+
//# sourceMappingURL=index.cjs.map
|
|
119
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/**\r\n * @suucha/ads-adsense\r\n *\r\n * Google AdSense 广告管理实现。\r\n * 动态加载 pagead2 脚本,提供 mountSlot / unmountSlot / refresh / enableAutoAds。\r\n */\r\n\r\nimport type { AdSlotHandle, AdSlotOptions, IAdManager } from '@suucha/core';\r\n\r\nexport interface AdSenseOptions {\r\n /** 发布者 ID,必填,格式 'ca-pub-xxxxxxxxxxxxxxxx' */\r\n client: string;\r\n /** 是否启用自动广告,默认 false */\r\n autoAds?: boolean;\r\n /** 是否在 consent 未授予时不加载脚本 */\r\n deferUntilConsent?: boolean;\r\n /** 自定义脚本来源(用于测试或代理) */\r\n scriptSrc?: string;\r\n}\r\n\r\nexport interface AdSenseSlotOptions extends AdSlotOptions {\r\n /** 广告单元 ID(如 '1234567890') */\r\n slot?: string;\r\n /** 广告格式,默认 'auto' */\r\n format?: 'auto' | 'horizontal' | 'vertical' | 'rectangle';\r\n /** 是否响应式,默认 true */\r\n responsive?: boolean;\r\n}\r\n\r\ninterface AdSenseSlotHandleInternal extends AdSlotHandle {\r\n refresh(): void;\r\n}\r\n\r\ndeclare global {\r\n interface Window {\r\n adsbygoogle?: unknown[];\r\n }\r\n}\r\n\r\nconst DEFAULT_SCRIPT_SRC = 'https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js';\r\n\r\nlet nextSlotId = 1;\r\n\r\nexport class AdSenseManager implements IAdManager {\r\n private readonly options: Required<AdSenseOptions>;\r\n private loaded = false;\r\n private readonly slots = new Map<string, AdSenseSlotHandleInternal>();\r\n\r\n constructor(options: AdSenseOptions) {\r\n if (!options.client || !options.client.startsWith('ca-pub-')) {\r\n throw new Error(\r\n `[AdSenseManager] client must start with 'ca-pub-', got: ${options.client}`,\r\n );\r\n }\r\n this.options = {\r\n autoAds: false,\r\n deferUntilConsent: false,\r\n scriptSrc: DEFAULT_SCRIPT_SRC,\r\n ...options,\r\n };\r\n\r\n if (!this.options.deferUntilConsent) {\r\n this.load();\r\n }\r\n\r\n if (this.options.autoAds) {\r\n this.enableAutoAds();\r\n }\r\n }\r\n\r\n /**\r\n * 加载 AdSense 脚本\r\n */\r\n load(): void {\r\n if (this.loaded) return;\r\n if (typeof document === 'undefined') return;\r\n\r\n const script = document.createElement('script');\r\n script.async = true;\r\n script.src = `${this.options.scriptSrc}?client=${this.options.client}`;\r\n script.crossOrigin = 'anonymous';\r\n document.head.appendChild(script);\r\n\r\n window.adsbygoogle = window.adsbygoogle || [];\r\n this.loaded = true;\r\n }\r\n\r\n /**\r\n * 启用自动广告(AdSense 自动选择位置)\r\n */\r\n enableAutoAds(): void {\r\n if (typeof window === 'undefined' || !window.adsbygoogle) return;\r\n window.adsbygoogle.push({ google_ad_client: this.options.client });\r\n }\r\n\r\n /**\r\n * 挂载广告位到 DOM\r\n */\r\n async mountSlot(slotOptions: AdSenseSlotOptions): Promise<AdSenseSlotHandleInternal> {\r\n if (typeof document === 'undefined') {\r\n throw new Error('[AdSenseManager] mountSlot requires a browser environment');\r\n }\r\n const container =\r\n typeof slotOptions.container === 'string'\r\n ? document.querySelector<HTMLElement>(slotOptions.container)\r\n : slotOptions.container;\r\n if (!container) {\r\n throw new Error(\r\n `[AdSenseManager] Container not found: ${slotOptions.container}`,\r\n );\r\n }\r\n\r\n const ins = document.createElement('ins');\r\n ins.className = 'adsbygoogle';\r\n ins.style.display = 'block';\r\n ins.setAttribute('data-ad-client', this.options.client);\r\n if (slotOptions.slot) {\r\n ins.setAttribute('data-ad-slot', slotOptions.slot);\r\n }\r\n ins.setAttribute(\r\n 'data-ad-format',\r\n slotOptions.format ?? 'auto',\r\n );\r\n if (slotOptions.responsive !== false) {\r\n ins.setAttribute('data-full-width-responsive', 'true');\r\n }\r\n container.appendChild(ins);\r\n\r\n if (window.adsbygoogle) {\r\n window.adsbygoogle.push({});\r\n }\r\n\r\n const id = `adsense_slot_${nextSlotId++}`;\r\n const handle: AdSenseSlotHandleInternal = {\r\n id,\r\n slot: slotOptions.slot ?? '',\r\n refresh: () => {\r\n if (window.adsbygoogle) {\r\n window.adsbygoogle.push({ refresh: () => {} });\r\n }\r\n },\r\n destroy: () => {\r\n ins.remove();\r\n this.slots.delete(id);\r\n },\r\n };\r\n this.slots.set(id, handle);\r\n return handle;\r\n }\r\n\r\n /**\r\n * 卸载广告位\r\n */\r\n unmountSlot(handle: AdSenseSlotHandleInternal): void {\r\n handle.destroy();\r\n }\r\n\r\n /**\r\n * 刷新广告位(重新竞价)\r\n */\r\n refresh(handle: AdSenseSlotHandleInternal): void {\r\n handle.refresh();\r\n }\r\n}\r\n\r\nexport type { AdSenseSlotHandleInternal };\r\n"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { IAdManager, AdSlotOptions, AdSlotHandle } from '@suucha/core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @suucha/ads-adsense
|
|
5
|
+
*
|
|
6
|
+
* Google AdSense 广告管理实现。
|
|
7
|
+
* 动态加载 pagead2 脚本,提供 mountSlot / unmountSlot / refresh / enableAutoAds。
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
interface AdSenseOptions {
|
|
11
|
+
/** 发布者 ID,必填,格式 'ca-pub-xxxxxxxxxxxxxxxx' */
|
|
12
|
+
client: string;
|
|
13
|
+
/** 是否启用自动广告,默认 false */
|
|
14
|
+
autoAds?: boolean;
|
|
15
|
+
/** 是否在 consent 未授予时不加载脚本 */
|
|
16
|
+
deferUntilConsent?: boolean;
|
|
17
|
+
/** 自定义脚本来源(用于测试或代理) */
|
|
18
|
+
scriptSrc?: string;
|
|
19
|
+
}
|
|
20
|
+
interface AdSenseSlotOptions extends AdSlotOptions {
|
|
21
|
+
/** 广告单元 ID(如 '1234567890') */
|
|
22
|
+
slot?: string;
|
|
23
|
+
/** 广告格式,默认 'auto' */
|
|
24
|
+
format?: 'auto' | 'horizontal' | 'vertical' | 'rectangle';
|
|
25
|
+
/** 是否响应式,默认 true */
|
|
26
|
+
responsive?: boolean;
|
|
27
|
+
}
|
|
28
|
+
interface AdSenseSlotHandleInternal extends AdSlotHandle {
|
|
29
|
+
refresh(): void;
|
|
30
|
+
}
|
|
31
|
+
declare global {
|
|
32
|
+
interface Window {
|
|
33
|
+
adsbygoogle?: unknown[];
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
declare class AdSenseManager implements IAdManager {
|
|
37
|
+
private readonly options;
|
|
38
|
+
private loaded;
|
|
39
|
+
private readonly slots;
|
|
40
|
+
constructor(options: AdSenseOptions);
|
|
41
|
+
/**
|
|
42
|
+
* 加载 AdSense 脚本
|
|
43
|
+
*/
|
|
44
|
+
load(): void;
|
|
45
|
+
/**
|
|
46
|
+
* 启用自动广告(AdSense 自动选择位置)
|
|
47
|
+
*/
|
|
48
|
+
enableAutoAds(): void;
|
|
49
|
+
/**
|
|
50
|
+
* 挂载广告位到 DOM
|
|
51
|
+
*/
|
|
52
|
+
mountSlot(slotOptions: AdSenseSlotOptions): Promise<AdSenseSlotHandleInternal>;
|
|
53
|
+
/**
|
|
54
|
+
* 卸载广告位
|
|
55
|
+
*/
|
|
56
|
+
unmountSlot(handle: AdSenseSlotHandleInternal): void;
|
|
57
|
+
/**
|
|
58
|
+
* 刷新广告位(重新竞价)
|
|
59
|
+
*/
|
|
60
|
+
refresh(handle: AdSenseSlotHandleInternal): void;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export { AdSenseManager, type AdSenseOptions, type AdSenseSlotHandleInternal, type AdSenseSlotOptions };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { IAdManager, AdSlotOptions, AdSlotHandle } from '@suucha/core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @suucha/ads-adsense
|
|
5
|
+
*
|
|
6
|
+
* Google AdSense 广告管理实现。
|
|
7
|
+
* 动态加载 pagead2 脚本,提供 mountSlot / unmountSlot / refresh / enableAutoAds。
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
interface AdSenseOptions {
|
|
11
|
+
/** 发布者 ID,必填,格式 'ca-pub-xxxxxxxxxxxxxxxx' */
|
|
12
|
+
client: string;
|
|
13
|
+
/** 是否启用自动广告,默认 false */
|
|
14
|
+
autoAds?: boolean;
|
|
15
|
+
/** 是否在 consent 未授予时不加载脚本 */
|
|
16
|
+
deferUntilConsent?: boolean;
|
|
17
|
+
/** 自定义脚本来源(用于测试或代理) */
|
|
18
|
+
scriptSrc?: string;
|
|
19
|
+
}
|
|
20
|
+
interface AdSenseSlotOptions extends AdSlotOptions {
|
|
21
|
+
/** 广告单元 ID(如 '1234567890') */
|
|
22
|
+
slot?: string;
|
|
23
|
+
/** 广告格式,默认 'auto' */
|
|
24
|
+
format?: 'auto' | 'horizontal' | 'vertical' | 'rectangle';
|
|
25
|
+
/** 是否响应式,默认 true */
|
|
26
|
+
responsive?: boolean;
|
|
27
|
+
}
|
|
28
|
+
interface AdSenseSlotHandleInternal extends AdSlotHandle {
|
|
29
|
+
refresh(): void;
|
|
30
|
+
}
|
|
31
|
+
declare global {
|
|
32
|
+
interface Window {
|
|
33
|
+
adsbygoogle?: unknown[];
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
declare class AdSenseManager implements IAdManager {
|
|
37
|
+
private readonly options;
|
|
38
|
+
private loaded;
|
|
39
|
+
private readonly slots;
|
|
40
|
+
constructor(options: AdSenseOptions);
|
|
41
|
+
/**
|
|
42
|
+
* 加载 AdSense 脚本
|
|
43
|
+
*/
|
|
44
|
+
load(): void;
|
|
45
|
+
/**
|
|
46
|
+
* 启用自动广告(AdSense 自动选择位置)
|
|
47
|
+
*/
|
|
48
|
+
enableAutoAds(): void;
|
|
49
|
+
/**
|
|
50
|
+
* 挂载广告位到 DOM
|
|
51
|
+
*/
|
|
52
|
+
mountSlot(slotOptions: AdSenseSlotOptions): Promise<AdSenseSlotHandleInternal>;
|
|
53
|
+
/**
|
|
54
|
+
* 卸载广告位
|
|
55
|
+
*/
|
|
56
|
+
unmountSlot(handle: AdSenseSlotHandleInternal): void;
|
|
57
|
+
/**
|
|
58
|
+
* 刷新广告位(重新竞价)
|
|
59
|
+
*/
|
|
60
|
+
refresh(handle: AdSenseSlotHandleInternal): void;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export { AdSenseManager, type AdSenseOptions, type AdSenseSlotHandleInternal, type AdSenseSlotOptions };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
|
+
|
|
5
|
+
// src/index.ts
|
|
6
|
+
var DEFAULT_SCRIPT_SRC = "https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js";
|
|
7
|
+
var nextSlotId = 1;
|
|
8
|
+
var AdSenseManager = class {
|
|
9
|
+
constructor(options) {
|
|
10
|
+
__publicField(this, "options");
|
|
11
|
+
__publicField(this, "loaded", false);
|
|
12
|
+
__publicField(this, "slots", /* @__PURE__ */ new Map());
|
|
13
|
+
if (!options.client || !options.client.startsWith("ca-pub-")) {
|
|
14
|
+
throw new Error(
|
|
15
|
+
`[AdSenseManager] client must start with 'ca-pub-', got: ${options.client}`
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
this.options = {
|
|
19
|
+
autoAds: false,
|
|
20
|
+
deferUntilConsent: false,
|
|
21
|
+
scriptSrc: DEFAULT_SCRIPT_SRC,
|
|
22
|
+
...options
|
|
23
|
+
};
|
|
24
|
+
if (!this.options.deferUntilConsent) {
|
|
25
|
+
this.load();
|
|
26
|
+
}
|
|
27
|
+
if (this.options.autoAds) {
|
|
28
|
+
this.enableAutoAds();
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* 加载 AdSense 脚本
|
|
33
|
+
*/
|
|
34
|
+
load() {
|
|
35
|
+
if (this.loaded) return;
|
|
36
|
+
if (typeof document === "undefined") return;
|
|
37
|
+
const script = document.createElement("script");
|
|
38
|
+
script.async = true;
|
|
39
|
+
script.src = `${this.options.scriptSrc}?client=${this.options.client}`;
|
|
40
|
+
script.crossOrigin = "anonymous";
|
|
41
|
+
document.head.appendChild(script);
|
|
42
|
+
window.adsbygoogle = window.adsbygoogle || [];
|
|
43
|
+
this.loaded = true;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* 启用自动广告(AdSense 自动选择位置)
|
|
47
|
+
*/
|
|
48
|
+
enableAutoAds() {
|
|
49
|
+
if (typeof window === "undefined" || !window.adsbygoogle) return;
|
|
50
|
+
window.adsbygoogle.push({ google_ad_client: this.options.client });
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* 挂载广告位到 DOM
|
|
54
|
+
*/
|
|
55
|
+
async mountSlot(slotOptions) {
|
|
56
|
+
if (typeof document === "undefined") {
|
|
57
|
+
throw new Error("[AdSenseManager] mountSlot requires a browser environment");
|
|
58
|
+
}
|
|
59
|
+
const container = typeof slotOptions.container === "string" ? document.querySelector(slotOptions.container) : slotOptions.container;
|
|
60
|
+
if (!container) {
|
|
61
|
+
throw new Error(
|
|
62
|
+
`[AdSenseManager] Container not found: ${slotOptions.container}`
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
const ins = document.createElement("ins");
|
|
66
|
+
ins.className = "adsbygoogle";
|
|
67
|
+
ins.style.display = "block";
|
|
68
|
+
ins.setAttribute("data-ad-client", this.options.client);
|
|
69
|
+
if (slotOptions.slot) {
|
|
70
|
+
ins.setAttribute("data-ad-slot", slotOptions.slot);
|
|
71
|
+
}
|
|
72
|
+
ins.setAttribute(
|
|
73
|
+
"data-ad-format",
|
|
74
|
+
slotOptions.format ?? "auto"
|
|
75
|
+
);
|
|
76
|
+
if (slotOptions.responsive !== false) {
|
|
77
|
+
ins.setAttribute("data-full-width-responsive", "true");
|
|
78
|
+
}
|
|
79
|
+
container.appendChild(ins);
|
|
80
|
+
if (window.adsbygoogle) {
|
|
81
|
+
window.adsbygoogle.push({});
|
|
82
|
+
}
|
|
83
|
+
const id = `adsense_slot_${nextSlotId++}`;
|
|
84
|
+
const handle = {
|
|
85
|
+
id,
|
|
86
|
+
slot: slotOptions.slot ?? "",
|
|
87
|
+
refresh: () => {
|
|
88
|
+
if (window.adsbygoogle) {
|
|
89
|
+
window.adsbygoogle.push({ refresh: () => {
|
|
90
|
+
} });
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
destroy: () => {
|
|
94
|
+
ins.remove();
|
|
95
|
+
this.slots.delete(id);
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
this.slots.set(id, handle);
|
|
99
|
+
return handle;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* 卸载广告位
|
|
103
|
+
*/
|
|
104
|
+
unmountSlot(handle) {
|
|
105
|
+
handle.destroy();
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* 刷新广告位(重新竞价)
|
|
109
|
+
*/
|
|
110
|
+
refresh(handle) {
|
|
111
|
+
handle.refresh();
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
export { AdSenseManager };
|
|
116
|
+
//# sourceMappingURL=index.js.map
|
|
117
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\r\n * @suucha/ads-adsense\r\n *\r\n * Google AdSense 广告管理实现。\r\n * 动态加载 pagead2 脚本,提供 mountSlot / unmountSlot / refresh / enableAutoAds。\r\n */\r\n\r\nimport type { AdSlotHandle, AdSlotOptions, IAdManager } from '@suucha/core';\r\n\r\nexport interface AdSenseOptions {\r\n /** 发布者 ID,必填,格式 'ca-pub-xxxxxxxxxxxxxxxx' */\r\n client: string;\r\n /** 是否启用自动广告,默认 false */\r\n autoAds?: boolean;\r\n /** 是否在 consent 未授予时不加载脚本 */\r\n deferUntilConsent?: boolean;\r\n /** 自定义脚本来源(用于测试或代理) */\r\n scriptSrc?: string;\r\n}\r\n\r\nexport interface AdSenseSlotOptions extends AdSlotOptions {\r\n /** 广告单元 ID(如 '1234567890') */\r\n slot?: string;\r\n /** 广告格式,默认 'auto' */\r\n format?: 'auto' | 'horizontal' | 'vertical' | 'rectangle';\r\n /** 是否响应式,默认 true */\r\n responsive?: boolean;\r\n}\r\n\r\ninterface AdSenseSlotHandleInternal extends AdSlotHandle {\r\n refresh(): void;\r\n}\r\n\r\ndeclare global {\r\n interface Window {\r\n adsbygoogle?: unknown[];\r\n }\r\n}\r\n\r\nconst DEFAULT_SCRIPT_SRC = 'https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js';\r\n\r\nlet nextSlotId = 1;\r\n\r\nexport class AdSenseManager implements IAdManager {\r\n private readonly options: Required<AdSenseOptions>;\r\n private loaded = false;\r\n private readonly slots = new Map<string, AdSenseSlotHandleInternal>();\r\n\r\n constructor(options: AdSenseOptions) {\r\n if (!options.client || !options.client.startsWith('ca-pub-')) {\r\n throw new Error(\r\n `[AdSenseManager] client must start with 'ca-pub-', got: ${options.client}`,\r\n );\r\n }\r\n this.options = {\r\n autoAds: false,\r\n deferUntilConsent: false,\r\n scriptSrc: DEFAULT_SCRIPT_SRC,\r\n ...options,\r\n };\r\n\r\n if (!this.options.deferUntilConsent) {\r\n this.load();\r\n }\r\n\r\n if (this.options.autoAds) {\r\n this.enableAutoAds();\r\n }\r\n }\r\n\r\n /**\r\n * 加载 AdSense 脚本\r\n */\r\n load(): void {\r\n if (this.loaded) return;\r\n if (typeof document === 'undefined') return;\r\n\r\n const script = document.createElement('script');\r\n script.async = true;\r\n script.src = `${this.options.scriptSrc}?client=${this.options.client}`;\r\n script.crossOrigin = 'anonymous';\r\n document.head.appendChild(script);\r\n\r\n window.adsbygoogle = window.adsbygoogle || [];\r\n this.loaded = true;\r\n }\r\n\r\n /**\r\n * 启用自动广告(AdSense 自动选择位置)\r\n */\r\n enableAutoAds(): void {\r\n if (typeof window === 'undefined' || !window.adsbygoogle) return;\r\n window.adsbygoogle.push({ google_ad_client: this.options.client });\r\n }\r\n\r\n /**\r\n * 挂载广告位到 DOM\r\n */\r\n async mountSlot(slotOptions: AdSenseSlotOptions): Promise<AdSenseSlotHandleInternal> {\r\n if (typeof document === 'undefined') {\r\n throw new Error('[AdSenseManager] mountSlot requires a browser environment');\r\n }\r\n const container =\r\n typeof slotOptions.container === 'string'\r\n ? document.querySelector<HTMLElement>(slotOptions.container)\r\n : slotOptions.container;\r\n if (!container) {\r\n throw new Error(\r\n `[AdSenseManager] Container not found: ${slotOptions.container}`,\r\n );\r\n }\r\n\r\n const ins = document.createElement('ins');\r\n ins.className = 'adsbygoogle';\r\n ins.style.display = 'block';\r\n ins.setAttribute('data-ad-client', this.options.client);\r\n if (slotOptions.slot) {\r\n ins.setAttribute('data-ad-slot', slotOptions.slot);\r\n }\r\n ins.setAttribute(\r\n 'data-ad-format',\r\n slotOptions.format ?? 'auto',\r\n );\r\n if (slotOptions.responsive !== false) {\r\n ins.setAttribute('data-full-width-responsive', 'true');\r\n }\r\n container.appendChild(ins);\r\n\r\n if (window.adsbygoogle) {\r\n window.adsbygoogle.push({});\r\n }\r\n\r\n const id = `adsense_slot_${nextSlotId++}`;\r\n const handle: AdSenseSlotHandleInternal = {\r\n id,\r\n slot: slotOptions.slot ?? '',\r\n refresh: () => {\r\n if (window.adsbygoogle) {\r\n window.adsbygoogle.push({ refresh: () => {} });\r\n }\r\n },\r\n destroy: () => {\r\n ins.remove();\r\n this.slots.delete(id);\r\n },\r\n };\r\n this.slots.set(id, handle);\r\n return handle;\r\n }\r\n\r\n /**\r\n * 卸载广告位\r\n */\r\n unmountSlot(handle: AdSenseSlotHandleInternal): void {\r\n handle.destroy();\r\n }\r\n\r\n /**\r\n * 刷新广告位(重新竞价)\r\n */\r\n refresh(handle: AdSenseSlotHandleInternal): void {\r\n handle.refresh();\r\n }\r\n}\r\n\r\nexport type { AdSenseSlotHandleInternal };\r\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@suucha/ads-adsense",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Google AdSense ad manager for Suucha Web SDK",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"require": "./dist/index.cjs"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"README.md"
|
|
19
|
+
],
|
|
20
|
+
"keywords": [
|
|
21
|
+
"suucha",
|
|
22
|
+
"ads",
|
|
23
|
+
"adsense",
|
|
24
|
+
"google"
|
|
25
|
+
],
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"author": "Suucha Studio",
|
|
28
|
+
"homepage": "https://github.com/suucha/Suucha.Web.Core#readme",
|
|
29
|
+
"repository": {
|
|
30
|
+
"type": "git",
|
|
31
|
+
"url": "git+https://github.com/suucha/Suucha.Web.Core.git",
|
|
32
|
+
"directory": "packages/ads-adsense"
|
|
33
|
+
},
|
|
34
|
+
"bugs": {
|
|
35
|
+
"url": "https://github.com/suucha/Suucha.Web.Core/issues"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"@suucha/core": "0.1.0"
|
|
39
|
+
},
|
|
40
|
+
"publishConfig": {
|
|
41
|
+
"access": "public"
|
|
42
|
+
},
|
|
43
|
+
"scripts": {
|
|
44
|
+
"build": "tsup",
|
|
45
|
+
"dev": "tsup --watch",
|
|
46
|
+
"typecheck": "tsc --noEmit"
|
|
47
|
+
}
|
|
48
|
+
}
|